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

Unified Diff: third_party/WebKit/Source/core/animation/KeyframeEffectReadOnly.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 side-by-side diff with in-line comments
Download patch
Index: third_party/WebKit/Source/core/animation/KeyframeEffectReadOnly.cpp
diff --git a/third_party/WebKit/Source/core/animation/KeyframeEffectReadOnly.cpp b/third_party/WebKit/Source/core/animation/KeyframeEffectReadOnly.cpp
index 721ec23998fabdf961947d9e22d362a9c58edf99..c7b469e6f7050ebbf58e418fcb431880c41c6df2 100644
--- a/third_party/WebKit/Source/core/animation/KeyframeEffectReadOnly.cpp
+++ b/third_party/WebKit/Source/core/animation/KeyframeEffectReadOnly.cpp
@@ -6,13 +6,21 @@
#include "bindings/core/v8/Dictionary.h"
#include "bindings/core/v8/ExceptionState.h"
+#include "core/animation/Animation.h"
+#include "core/animation/CompositorAnimations.h"
#include "core/animation/EffectInput.h"
+#include "core/animation/ElementAnimations.h"
+#include "core/animation/Interpolation.h"
#include "core/animation/KeyframeEffect.h"
#include "core/animation/KeyframeEffectOptions.h"
+#include "core/animation/PropertyHandle.h"
#include "core/animation/SampledEffect.h"
#include "core/animation/TimingInput.h"
#include "core/dom/Element.h"
+#include "core/dom/NodeComputedStyle.h"
#include "core/frame/UseCounter.h"
+#include "core/paint/PaintLayer.h"
+#include "core/svg/SVGElement.h"
namespace blink {
@@ -60,6 +68,273 @@ KeyframeEffectReadOnly::KeyframeEffectReadOnly(Element* target,
m_sampledEffect(nullptr),
m_priority(priority) {}
+void KeyframeEffectReadOnly::attach(Animation* animation) {
+ if (m_target) {
+ m_target->ensureElementAnimations().animations().add(animation);
+ m_target->setNeedsAnimationStyleRecalc();
+ if (RuntimeEnabledFeatures::webAnimationsSVGEnabled() &&
+ m_target->isSVGElement())
+ toSVGElement(m_target)->setWebAnimationsPending();
+ }
+ AnimationEffectReadOnly::attach(animation);
+}
+
+void KeyframeEffectReadOnly::detach() {
+ if (m_target)
+ m_target->elementAnimations()->animations().remove(animation());
+ if (m_sampledEffect)
+ clearEffects();
+ AnimationEffectReadOnly::detach();
+}
+
+void KeyframeEffectReadOnly::specifiedTimingChanged() {
+ if (animation()) {
+ // FIXME: Needs to consider groups when added.
+ DCHECK_EQ(animation()->effect(), this);
+ animation()->setCompositorPending(true);
+ }
+}
+
+static AnimationStack& ensureAnimationStack(Element* element) {
+ return element->ensureElementAnimations().animationStack();
+}
+
+bool KeyframeEffectReadOnly::hasMultipleTransformProperties() const {
+ if (!m_target->computedStyle())
+ return false;
+
+ unsigned transformPropertyCount = 0;
+ if (m_target->computedStyle()->hasTransformOperations())
+ transformPropertyCount++;
+ if (m_target->computedStyle()->rotate())
+ transformPropertyCount++;
+ if (m_target->computedStyle()->scale())
+ transformPropertyCount++;
+ if (m_target->computedStyle()->translate())
+ transformPropertyCount++;
+ return transformPropertyCount > 1;
+}
+
+// Returns true if transform, translate, rotate or scale is composited
+// and a motion path or other transform properties
+// has been introduced on the element
+bool KeyframeEffectReadOnly::hasIncompatibleStyle() {
+ if (!m_target->computedStyle())
+ return false;
+
+ bool affectsTransform =
+ animation()->affects(*m_target, CSSPropertyTransform) ||
+ animation()->affects(*m_target, CSSPropertyScale) ||
+ animation()->affects(*m_target, CSSPropertyRotate) ||
+ animation()->affects(*m_target, CSSPropertyTranslate);
+
+ if (animation()->hasActiveAnimationsOnCompositor()) {
+ if (m_target->computedStyle()->hasOffset() && affectsTransform)
+ return true;
+ return hasMultipleTransformProperties();
+ }
+
+ return false;
+}
+
+void KeyframeEffectReadOnly::applyEffects() {
+ DCHECK(isInEffect());
+ DCHECK(animation());
+ if (!m_target || !m_model)
+ return;
+
+ if (hasIncompatibleStyle())
+ animation()->cancelAnimationOnCompositor();
+
+ double iteration = currentIteration();
+ DCHECK_GE(iteration, 0);
+ bool changed = false;
+ if (m_sampledEffect) {
+ changed = m_model->sample(clampTo<int>(iteration, 0), progress(),
+ iterationDuration(),
+ m_sampledEffect->mutableInterpolations());
+ } else {
+ Vector<RefPtr<Interpolation>> interpolations;
+ m_model->sample(clampTo<int>(iteration, 0), progress(), iterationDuration(),
+ interpolations);
+ if (!interpolations.isEmpty()) {
+ SampledEffect* sampledEffect = SampledEffect::create(this);
+ sampledEffect->mutableInterpolations().swap(interpolations);
+ m_sampledEffect = sampledEffect;
+ ensureAnimationStack(m_target).add(sampledEffect);
+ changed = true;
+ } else {
+ return;
+ }
+ }
+
+ if (changed) {
+ m_target->setNeedsAnimationStyleRecalc();
+ if (RuntimeEnabledFeatures::webAnimationsSVGEnabled() &&
+ m_target->isSVGElement())
+ toSVGElement(*m_target).setWebAnimationsPending();
+ }
+}
+
+void KeyframeEffectReadOnly::clearEffects() {
+ DCHECK(animation());
+ DCHECK(m_sampledEffect);
+
+ m_sampledEffect->clear();
+ m_sampledEffect = nullptr;
+ restartAnimationOnCompositor();
+ m_target->setNeedsAnimationStyleRecalc();
+ if (RuntimeEnabledFeatures::webAnimationsSVGEnabled() &&
+ m_target->isSVGElement())
+ toSVGElement(*m_target).clearWebAnimatedAttributes();
+ invalidate();
+}
+
+void KeyframeEffectReadOnly::updateChildrenAndEffects() const {
+ if (!m_model)
+ return;
+ DCHECK(animation());
+ if (isInEffect() && !animation()->effectSuppressed())
+ const_cast<KeyframeEffectReadOnly*>(this)->applyEffects();
+ else if (m_sampledEffect)
+ const_cast<KeyframeEffectReadOnly*>(this)->clearEffects();
+}
+
+double KeyframeEffectReadOnly::calculateTimeToEffectChange(
+ bool forwards,
+ double localTime,
+ double timeToNextIteration) const {
+ const double startTime = specifiedTiming().startDelay;
+ const double endTimeMinusEndDelay = startTime + activeDurationInternal();
+ const double endTime = endTimeMinusEndDelay + specifiedTiming().endDelay;
+ const double afterTime = std::min(endTimeMinusEndDelay, endTime);
+
+ switch (getPhase()) {
+ case PhaseNone:
+ return std::numeric_limits<double>::infinity();
+ case PhaseBefore:
+ DCHECK_GE(startTime, localTime);
+ return forwards ? startTime - localTime
+ : std::numeric_limits<double>::infinity();
+ case PhaseActive:
+ if (forwards) {
+ // Need service to apply fill / fire events.
+ const double timeToEnd = afterTime - localTime;
+ if (requiresIterationEvents()) {
+ return std::min(timeToEnd, timeToNextIteration);
+ }
+ return timeToEnd;
+ }
+ return 0;
+ case PhaseAfter:
+ DCHECK_GE(localTime, afterTime);
+ // If this KeyframeEffect is still in effect then it will need to update
+ // when its parent goes out of effect. We have no way of knowing when
+ // that will be, however, so the parent will need to supply it.
+ return forwards ? std::numeric_limits<double>::infinity()
+ : localTime - afterTime;
+ default:
+ NOTREACHED();
+ return std::numeric_limits<double>::infinity();
+ }
+}
+
+void KeyframeEffectReadOnly::notifySampledEffectRemovedFromAnimationStack() {
+ m_sampledEffect = nullptr;
+}
+
+bool KeyframeEffectReadOnly::isCandidateForAnimationOnCompositor(
+ double animationPlaybackRate) const {
+ // Do not put transforms on compositor if more than one of them are defined
+ // in computed style because they need to be explicitly ordered
+ if (!model() || !m_target ||
+ (m_target->computedStyle() && m_target->computedStyle()->hasOffset()) ||
+ hasMultipleTransformProperties())
+ return false;
+
+ return CompositorAnimations::isCandidateForAnimationOnCompositor(
+ specifiedTiming(), *m_target, animation(), *model(),
+ animationPlaybackRate);
+}
+
+bool KeyframeEffectReadOnly::maybeStartAnimationOnCompositor(
+ int group,
+ double startTime,
+ double currentTime,
+ double animationPlaybackRate) {
+ DCHECK(!hasActiveAnimationsOnCompositor());
+ if (!isCandidateForAnimationOnCompositor(animationPlaybackRate))
+ return false;
+ if (!CompositorAnimations::canStartAnimationOnCompositor(*m_target))
+ return false;
+ CompositorAnimations::startAnimationOnCompositor(
+ *m_target, group, startTime, currentTime, specifiedTiming(), *animation(),
+ *model(), m_compositorAnimationIds, animationPlaybackRate);
+ DCHECK(!m_compositorAnimationIds.isEmpty());
+ return true;
+}
+
+bool KeyframeEffectReadOnly::hasActiveAnimationsOnCompositor() const {
+ return !m_compositorAnimationIds.isEmpty();
+}
+
+bool KeyframeEffectReadOnly::hasActiveAnimationsOnCompositor(
+ CSSPropertyID property) const {
+ return hasActiveAnimationsOnCompositor() && affects(PropertyHandle(property));
+}
+
+bool KeyframeEffectReadOnly::affects(PropertyHandle property) const {
+ return m_model && m_model->affects(property);
+}
+
+bool KeyframeEffectReadOnly::cancelAnimationOnCompositor() {
+ // FIXME: cancelAnimationOnCompositor is called from withins style recalc.
+ // This queries compositingState, which is not necessarily up to date.
+ // https://code.google.com/p/chromium/issues/detail?id=339847
+ DisableCompositingQueryAsserts disabler;
+ if (!hasActiveAnimationsOnCompositor())
+ return false;
+ if (!m_target || !m_target->layoutObject())
+ return false;
+ DCHECK(animation());
+ for (const auto& compositorAnimationId : m_compositorAnimationIds) {
+ CompositorAnimations::cancelAnimationOnCompositor(*m_target, *animation(),
+ compositorAnimationId);
+ }
+ m_compositorAnimationIds.clear();
+ return true;
+}
+
+void KeyframeEffectReadOnly::restartAnimationOnCompositor() {
+ if (cancelAnimationOnCompositor())
+ animation()->setCompositorPending(true);
+}
+
+void KeyframeEffectReadOnly::cancelIncompatibleAnimationsOnCompositor() {
+ if (m_target && animation() && model()) {
+ CompositorAnimations::cancelIncompatibleAnimationsOnCompositor(
+ *m_target, *animation(), *model());
+ }
+}
+
+void KeyframeEffectReadOnly::pauseAnimationForTestingOnCompositor(
+ double pauseTime) {
+ DCHECK(hasActiveAnimationsOnCompositor());
+ if (!m_target || !m_target->layoutObject())
+ return;
+ DCHECK(animation());
+ for (const auto& compositorAnimationId : m_compositorAnimationIds) {
+ CompositorAnimations::pauseAnimationForTestingOnCompositor(
+ *m_target, *animation(), compositorAnimationId, pauseTime);
+ }
+}
+
+void KeyframeEffectReadOnly::attachCompositedLayers() {
+ DCHECK(m_target);
+ DCHECK(animation());
+ CompositorAnimations::attachCompositedLayers(*m_target, *animation());
+}
+
DEFINE_TRACE(KeyframeEffectReadOnly) {
visitor->trace(m_target);
visitor->trace(m_model);

Powered by Google App Engine
This is Rietveld 408576698