summaryrefslogtreecommitdiffstats
path: root/chromium/third_party/WebKit/Source/core/animation
diff options
context:
space:
mode:
authorJocelyn Turcotte <jocelyn.turcotte@digia.com>2014-08-08 14:30:41 +0200
committerJocelyn Turcotte <jocelyn.turcotte@digia.com>2014-08-12 13:49:54 +0200
commitab0a50979b9eb4dfa3320eff7e187e41efedf7a9 (patch)
tree498dfb8a97ff3361a9f7486863a52bb4e26bb898 /chromium/third_party/WebKit/Source/core/animation
parent4ce69f7403811819800e7c5ae1318b2647e778d1 (diff)
Update Chromium to beta version 37.0.2062.68
Change-Id: I188e3b5aff1bec75566014291b654eb19f5bc8ca Reviewed-by: Andras Becsi <andras.becsi@digia.com>
Diffstat (limited to 'chromium/third_party/WebKit/Source/core/animation')
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/ActiveAnimations.cpp90
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/ActiveAnimations.h45
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimatableClipPathOperation.cpp15
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimatableClipPathOperation.h11
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimatableColor.cpp40
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimatableColor.h12
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimatableColorTest.cpp19
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimatableDouble.cpp26
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimatableDouble.h15
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimatableDoubleTest.cpp28
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimatableFilterOperations.cpp16
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimatableFilterOperations.h12
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimatableImage.cpp49
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimatableImage.h27
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimatableLength.cpp206
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimatableLength.h125
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimatableLengthBox.cpp21
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimatableLengthBox.h21
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimatableLengthBoxAndBool.cpp23
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimatableLengthBoxAndBool.h16
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimatableLengthPoint.cpp15
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimatableLengthPoint.h17
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimatableLengthPoint3D.cpp59
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimatableLengthPoint3D.h77
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimatableLengthSize.cpp15
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimatableLengthSize.h17
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimatableLengthTest.cpp378
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimatableNeutral.h10
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimatableNeutralTest.cpp9
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimatableRepeatable.cpp62
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimatableRepeatable.h21
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimatableSVGLength.cpp12
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimatableSVGLength.h21
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimatableSVGPaint.cpp27
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimatableSVGPaint.h40
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimatableShadow.cpp9
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimatableShadow.h11
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimatableShapeValue.cpp20
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimatableShapeValue.h11
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimatableStrokeDasharrayList.cpp49
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimatableStrokeDasharrayList.h21
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimatableStrokeDasharrayListTest.cpp24
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimatableTransform.cpp12
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimatableTransform.h9
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimatableUnknown.h28
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimatableUnknownTest.cpp15
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimatableValue.cpp25
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimatableValue.h34
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimatableValueKeyframe.cpp80
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimatableValueKeyframe.h75
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimatableValueTestHelper.cpp82
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimatableValueTestHelper.h11
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimatableValueTestHelperTest.cpp72
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimatableVisibility.cpp9
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimatableVisibility.h11
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/Animation.cpp218
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/Animation.h71
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/Animation.idl (renamed from chromium/third_party/WebKit/Source/core/animation/css/TransitionTimeline.h)25
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimationClock.cpp82
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimationClock.h38
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimationClockTest.cpp98
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimationEffect.h24
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimationEffect.idl10
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimationHelpers.h33
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimationHelpersTest.cpp24
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimationNode.cpp (renamed from chromium/third_party/WebKit/Source/core/animation/TimedItem.cpp)165
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimationNode.h (renamed from chromium/third_party/WebKit/Source/core/animation/TimedItem.h)107
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimationNode.idl (renamed from chromium/third_party/WebKit/Source/core/animation/css/TransitionTimeline.cpp)35
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimationNodeTest.cpp775
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimationNodeTiming.cpp180
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimationNodeTiming.h46
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimationPlayer.cpp460
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimationPlayer.h195
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimationPlayer.idl51
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimationPlayerTest.cpp737
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimationStack.cpp104
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimationStack.h27
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimationStackTest.cpp163
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimationTest.cpp467
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimationTestHelper.cpp32
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimationTestHelper.h23
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimationTimeline.cpp232
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimationTimeline.h (renamed from chromium/third_party/WebKit/Source/core/animation/DocumentTimeline.h)114
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimationTimeline.idl11
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimationTimelineTest.cpp (renamed from chromium/third_party/WebKit/Source/core/animation/DocumentTimelineTest.cpp)186
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimationTranslationUtil.cpp127
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimationTranslationUtil.h49
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/AnimationTranslationUtilTest.cpp115
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/CompositorAnimations.cpp202
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/CompositorAnimations.h5
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/CompositorAnimationsImpl.h10
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/CompositorAnimationsTest.cpp458
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/CompositorAnimationsTestHelper.h2
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/CompositorAnimationsTimingFunctionReverserTest.cpp24
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/CompositorPendingAnimations.cpp (renamed from chromium/third_party/WebKit/Source/core/animation/css/CSSPendingAnimations.cpp)64
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/CompositorPendingAnimations.h (renamed from chromium/third_party/WebKit/Source/core/animation/css/CSSPendingAnimations.h)26
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/DocumentAnimation.h19
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/DocumentAnimation.idl9
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/DocumentAnimations.cpp72
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/DocumentAnimations.h12
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/DocumentTimeline.cpp187
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/EffectInput.cpp128
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/EffectInput.h25
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/EffectInputTest.cpp125
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/ElementAnimation.cpp142
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/ElementAnimation.h65
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/ElementAnimation.idl10
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/ElementAnimationTest.cpp208
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/InertAnimation.cpp24
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/InertAnimation.h20
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/InterpolableValue.cpp75
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/InterpolableValue.h167
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/InterpolableValueTest.cpp105
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/InterpolationEffect.cpp42
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/InterpolationEffect.h66
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/InterpolationEffectTest.cpp98
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/Keyframe.h102
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/KeyframeAnimationEffect.cpp367
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/KeyframeAnimationEffect.h155
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/KeyframeAnimationEffectTest.cpp379
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/KeyframeEffectModel.cpp255
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/KeyframeEffectModel.h179
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/KeyframeEffectModelTest.cpp564
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/Player.cpp204
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/Player.h102
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/PlayerTest.cpp364
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/SampledEffect.cpp66
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/SampledEffect.h51
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/StringKeyframe.cpp152
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/StringKeyframe.h79
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/TimedItemTest.cpp782
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/Timing.h23
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/Timing.idl29
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/TimingCalculations.h (renamed from chromium/third_party/WebKit/Source/core/animation/TimedItemCalculations.h)44
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/TimingCalculationsTest.cpp (renamed from chromium/third_party/WebKit/Source/core/animation/TimedItemCalculationsTest.cpp)63
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/TimingInput.cpp154
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/TimingInput.h32
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/TimingInputTest.cpp181
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/css/CSSAnimatableValueFactory.cpp173
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/css/CSSAnimatableValueFactory.h6
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/css/CSSAnimationData.cpp54
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/css/CSSAnimationData.h61
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/css/CSSAnimations.cpp726
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/css/CSSAnimations.h146
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/css/CSSPropertyEquality.cpp318
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/css/CSSPropertyEquality.h21
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/css/CSSTimingData.cpp36
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/css/CSSTimingData.h50
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/css/CSSTransitionData.cpp37
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/css/CSSTransitionData.h81
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/interpolation/DefaultStyleInterpolation.h46
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/interpolation/DeferredLegacyStyleInterpolation.cpp152
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/interpolation/DeferredLegacyStyleInterpolation.h53
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/interpolation/DeferredLegacyStyleInterpolationTest.cpp94
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/interpolation/Interpolation.cpp63
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/interpolation/Interpolation.h47
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/interpolation/LegacyStyleInterpolation.h48
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/interpolation/LengthStyleInterpolation.cpp109
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/interpolation/LengthStyleInterpolation.h42
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/interpolation/LengthStyleInterpolationTest.cpp119
-rw-r--r--chromium/third_party/WebKit/Source/core/animation/interpolation/StyleInterpolation.h48
161 files changed, 10694 insertions, 5782 deletions
diff --git a/chromium/third_party/WebKit/Source/core/animation/ActiveAnimations.cpp b/chromium/third_party/WebKit/Source/core/animation/ActiveAnimations.cpp
index d27161d6a10..8743e5c4c8b 100644
--- a/chromium/third_party/WebKit/Source/core/animation/ActiveAnimations.cpp
+++ b/chromium/third_party/WebKit/Source/core/animation/ActiveAnimations.cpp
@@ -31,71 +31,71 @@
#include "config.h"
#include "core/animation/ActiveAnimations.h"
-#include "core/frame/animation/AnimationController.h"
#include "core/rendering/RenderObject.h"
namespace WebCore {
-bool shouldCompositeForActiveAnimations(const RenderObject& renderer)
+ActiveAnimations::~ActiveAnimations()
{
- ASSERT(RuntimeEnabledFeatures::webAnimationsCSSEnabled());
-
- if (!renderer.node() || !renderer.node()->isElementNode())
- return false;
-
- const Element* element = toElement(renderer.node());
- if (const ActiveAnimations* activeAnimations = element->activeAnimations()) {
- if (activeAnimations->hasActiveAnimations(CSSPropertyOpacity)
- || activeAnimations->hasActiveAnimations(CSSPropertyWebkitTransform)
- || activeAnimations->hasActiveAnimations(CSSPropertyWebkitFilter))
- return true;
- }
-
- return false;
+#if !ENABLE(OILPAN)
+ for (size_t i = 0; i < m_animations.size(); ++i)
+ m_animations[i]->notifyElementDestroyed();
+ m_animations.clear();
+#endif
}
-bool hasActiveAnimations(const RenderObject& renderer, CSSPropertyID property)
+void ActiveAnimations::addPlayer(AnimationPlayer* player)
{
- ASSERT(RuntimeEnabledFeatures::webAnimationsCSSEnabled());
-
- if (!renderer.node() || !renderer.node()->isElementNode())
- return false;
-
- const Element* element = toElement(renderer.node());
- if (const ActiveAnimations* activeAnimations = element->activeAnimations())
- return activeAnimations->hasActiveAnimations(property);
-
- return false;
+ ++m_players.add(player, 0).storedValue->value;
}
-bool hasActiveAnimationsOnCompositor(const RenderObject& renderer, CSSPropertyID property)
+void ActiveAnimations::removePlayer(AnimationPlayer* player)
{
- ASSERT(RuntimeEnabledFeatures::webAnimationsCSSEnabled());
-
- if (!renderer.node() || !renderer.node()->isElementNode())
- return false;
-
- const Element* element = toElement(renderer.node());
- if (const ActiveAnimations* activeAnimations = element->activeAnimations())
- return activeAnimations->hasActiveAnimationsOnCompositor(property);
-
- return false;
+ AnimationPlayerCountedSet::iterator it = m_players.find(player);
+ ASSERT(it != m_players.end());
+ ASSERT(it->value > 0);
+ --it->value;
+ if (!it->value)
+ m_players.remove(it);
}
-bool ActiveAnimations::hasActiveAnimations(CSSPropertyID property) const
+void ActiveAnimations::updateAnimationFlags(RenderStyle& style)
{
- return m_defaultStack.affects(property);
-}
+ for (AnimationPlayerCountedSet::const_iterator it = m_players.begin(); it != m_players.end(); ++it) {
+ const AnimationPlayer& player = *it->key;
+ ASSERT(player.source());
+ // FIXME: Needs to consider AnimationGroup once added.
+ ASSERT(player.source()->isAnimation());
+ const Animation& animation = *toAnimation(player.source());
+ if (animation.isCurrent()) {
+ if (animation.affects(CSSPropertyOpacity))
+ style.setHasCurrentOpacityAnimation(true);
+ if (animation.affects(CSSPropertyTransform))
+ style.setHasCurrentTransformAnimation(true);
+ if (animation.affects(CSSPropertyWebkitFilter))
+ style.setHasCurrentFilterAnimation(true);
+ }
+ }
-bool ActiveAnimations::hasActiveAnimationsOnCompositor(CSSPropertyID property) const
-{
- return m_defaultStack.hasActiveAnimationsOnCompositor(property);
+ if (style.hasCurrentOpacityAnimation())
+ style.setIsRunningOpacityAnimationOnCompositor(m_defaultStack.hasActiveAnimationsOnCompositor(CSSPropertyOpacity));
+ if (style.hasCurrentTransformAnimation())
+ style.setIsRunningTransformAnimationOnCompositor(m_defaultStack.hasActiveAnimationsOnCompositor(CSSPropertyTransform));
+ if (style.hasCurrentFilterAnimation())
+ style.setIsRunningFilterAnimationOnCompositor(m_defaultStack.hasActiveAnimationsOnCompositor(CSSPropertyWebkitFilter));
}
void ActiveAnimations::cancelAnimationOnCompositor()
{
- for (PlayerSet::iterator it = m_players.begin(); it != players().end(); ++it)
+ for (AnimationPlayerCountedSet::iterator it = m_players.begin(); it != m_players.end(); ++it)
it->key->cancelAnimationOnCompositor();
}
+void ActiveAnimations::trace(Visitor* visitor)
+{
+ visitor->trace(m_cssAnimations);
+ visitor->trace(m_defaultStack);
+ visitor->trace(m_players);
+}
+
} // namespace WebCore
diff --git a/chromium/third_party/WebKit/Source/core/animation/ActiveAnimations.h b/chromium/third_party/WebKit/Source/core/animation/ActiveAnimations.h
index b12a9bf95dd..ad5ba4b6891 100644
--- a/chromium/third_party/WebKit/Source/core/animation/ActiveAnimations.h
+++ b/chromium/third_party/WebKit/Source/core/animation/ActiveAnimations.h
@@ -44,15 +44,15 @@ class CSSAnimations;
class RenderObject;
class Element;
-// FIXME: Move these to CompositorAnimations
-bool shouldCompositeForActiveAnimations(const RenderObject&);
-bool hasActiveAnimations(const RenderObject&, CSSPropertyID);
-bool hasActiveAnimationsOnCompositor(const RenderObject&, CSSPropertyID);
-
-class ActiveAnimations {
+class ActiveAnimations : public NoBaseWillBeGarbageCollectedFinalized<ActiveAnimations> {
+ WTF_MAKE_NONCOPYABLE(ActiveAnimations);
public:
ActiveAnimations()
- : m_animationStyleChange(false) { }
+ : m_animationStyleChange(false)
+ {
+ }
+
+ ~ActiveAnimations();
// Animations that are currently active for this element, their effects will be applied
// during a style recalc. CSS Transitions are included in this stack.
@@ -63,27 +63,44 @@ public:
CSSAnimations& cssAnimations() { return m_cssAnimations; }
const CSSAnimations& cssAnimations() const { return m_cssAnimations; }
- typedef HashCountedSet<Player*> PlayerSet;
- // Players which have animations targeting this element.
- const PlayerSet& players() const { return m_players; }
- PlayerSet& players() { return m_players; }
+ typedef WillBeHeapHashMap<RawPtrWillBeWeakMember<AnimationPlayer>, int> AnimationPlayerCountedSet;
+ // AnimationPlayers which have animations targeting this element.
+ const AnimationPlayerCountedSet& players() const { return m_players; }
+ void addPlayer(AnimationPlayer*);
+ void removePlayer(AnimationPlayer*);
+#if ENABLE(OILPAN)
bool isEmpty() const { return m_defaultStack.isEmpty() && m_cssAnimations.isEmpty(); }
+#else
+ bool isEmpty() const { return m_defaultStack.isEmpty() && m_cssAnimations.isEmpty() && m_animations.isEmpty(); }
+#endif
- bool hasActiveAnimations(CSSPropertyID) const;
- bool hasActiveAnimationsOnCompositor(CSSPropertyID) const;
void cancelAnimationOnCompositor();
+ void updateAnimationFlags(RenderStyle&);
void setAnimationStyleChange(bool animationStyleChange) { m_animationStyleChange = animationStyleChange; }
+#if !ENABLE(OILPAN)
+ void addAnimation(Animation* animation) { m_animations.append(animation); }
+ void notifyAnimationDestroyed(Animation* animation) { m_animations.remove(m_animations.find(animation)); }
+#endif
+
+ void trace(Visitor*);
+
private:
bool isAnimationStyleChange() const { return m_animationStyleChange; }
AnimationStack m_defaultStack;
CSSAnimations m_cssAnimations;
- PlayerSet m_players;
+ AnimationPlayerCountedSet m_players;
bool m_animationStyleChange;
+#if !ENABLE(OILPAN)
+ // FIXME: Oilpan: This is to avoid a reference cycle that keeps Elements alive
+ // and won't be needed once the Node hierarchy becomes traceable.
+ Vector<Animation*> m_animations;
+#endif
+
// CSSAnimations checks if a style change is due to animation.
friend class CSSAnimations;
};
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimatableClipPathOperation.cpp b/chromium/third_party/WebKit/Source/core/animation/AnimatableClipPathOperation.cpp
index f539df4d1fb..1b1705a08c9 100644
--- a/chromium/third_party/WebKit/Source/core/animation/AnimatableClipPathOperation.cpp
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimatableClipPathOperation.cpp
@@ -33,19 +33,28 @@
namespace WebCore {
-PassRefPtr<AnimatableValue> AnimatableClipPathOperation::interpolateTo(const AnimatableValue* value, double fraction) const
+bool AnimatableClipPathOperation::usesDefaultInterpolationWith(const AnimatableValue* value) const
{
const AnimatableClipPathOperation* toOperation = toAnimatableClipPathOperation(value);
if (m_operation->type() != ClipPathOperation::SHAPE || toOperation->m_operation->type() != ClipPathOperation::SHAPE)
- return defaultInterpolateTo(this, value, fraction);
+ return true;
const BasicShape* fromShape = toShapeClipPathOperation(clipPathOperation())->basicShape();
const BasicShape* toShape = toShapeClipPathOperation(toOperation->clipPathOperation())->basicShape();
- if (!fromShape->canBlend(toShape))
+ return !fromShape->canBlend(toShape);
+}
+
+PassRefPtrWillBeRawPtr<AnimatableValue> AnimatableClipPathOperation::interpolateTo(const AnimatableValue* value, double fraction) const
+{
+ if (usesDefaultInterpolationWith(value))
return defaultInterpolateTo(this, value, fraction);
+ const AnimatableClipPathOperation* toOperation = toAnimatableClipPathOperation(value);
+ const BasicShape* fromShape = toShapeClipPathOperation(clipPathOperation())->basicShape();
+ const BasicShape* toShape = toShapeClipPathOperation(toOperation->clipPathOperation())->basicShape();
+
return AnimatableClipPathOperation::create(ShapeClipPathOperation::create(toShape->blend(fromShape, fraction)).get());
}
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimatableClipPathOperation.h b/chromium/third_party/WebKit/Source/core/animation/AnimatableClipPathOperation.h
index 0a2401f2bdb..0a0188d7bd8 100644
--- a/chromium/third_party/WebKit/Source/core/animation/AnimatableClipPathOperation.h
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimatableClipPathOperation.h
@@ -36,17 +36,20 @@
namespace WebCore {
-class AnimatableClipPathOperation : public AnimatableValue {
+class AnimatableClipPathOperation FINAL : public AnimatableValue {
public:
virtual ~AnimatableClipPathOperation() { }
- static PassRefPtr<AnimatableClipPathOperation> create(ClipPathOperation* operation)
+ static PassRefPtrWillBeRawPtr<AnimatableClipPathOperation> create(ClipPathOperation* operation)
{
- return adoptRef(new AnimatableClipPathOperation(operation));
+ return adoptRefWillBeNoop(new AnimatableClipPathOperation(operation));
}
ClipPathOperation* clipPathOperation() const { return m_operation.get(); }
+ virtual void trace(Visitor* visitor) OVERRIDE { AnimatableValue::trace(visitor); }
+
protected:
- virtual PassRefPtr<AnimatableValue> interpolateTo(const AnimatableValue*, double fraction) const OVERRIDE;
+ virtual PassRefPtrWillBeRawPtr<AnimatableValue> interpolateTo(const AnimatableValue*, double fraction) const OVERRIDE;
+ virtual bool usesDefaultInterpolationWith(const AnimatableValue*) const OVERRIDE;
private:
AnimatableClipPathOperation(ClipPathOperation* operation)
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimatableColor.cpp b/chromium/third_party/WebKit/Source/core/animation/AnimatableColor.cpp
index d501a81f4c1..8170b6cc801 100644
--- a/chromium/third_party/WebKit/Source/core/animation/AnimatableColor.cpp
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimatableColor.cpp
@@ -34,6 +34,15 @@
#include "platform/animation/AnimationUtilities.h"
#include "wtf/MathExtras.h"
+namespace {
+
+double square(double x)
+{
+ return x * x;
+}
+
+} // namespace
+
namespace WebCore {
AnimatableColorImpl::AnimatableColorImpl(float red, float green, float blue, float alpha)
@@ -67,14 +76,6 @@ AnimatableColorImpl AnimatableColorImpl::interpolateTo(const AnimatableColorImpl
blend(m_alpha, to.m_alpha, fraction));
}
-AnimatableColorImpl AnimatableColorImpl::addWith(const AnimatableColorImpl& addend) const
-{
- return AnimatableColorImpl(m_red + addend.m_red,
- m_green + addend.m_green,
- m_blue + addend.m_blue,
- m_alpha + addend.m_alpha);
-}
-
bool AnimatableColorImpl::operator==(const AnimatableColorImpl& other) const
{
return m_red == other.m_red
@@ -83,29 +84,36 @@ bool AnimatableColorImpl::operator==(const AnimatableColorImpl& other) const
&& m_alpha == other.m_alpha;
}
-PassRefPtr<AnimatableColor> AnimatableColor::create(const AnimatableColorImpl& color, const AnimatableColorImpl& visitedLinkColor)
+double AnimatableColorImpl::distanceTo(const AnimatableColorImpl& other) const
{
- return adoptRef(new AnimatableColor(color, visitedLinkColor));
+ return sqrt(square(m_red - other.m_red)
+ + square(m_green - other.m_green)
+ + square(m_blue - other.m_blue)
+ + square(m_alpha - other.m_alpha));
}
-PassRefPtr<AnimatableValue> AnimatableColor::interpolateTo(const AnimatableValue* value, double fraction) const
+PassRefPtrWillBeRawPtr<AnimatableColor> AnimatableColor::create(const AnimatableColorImpl& color, const AnimatableColorImpl& visitedLinkColor)
+{
+ return adoptRefWillBeNoop(new AnimatableColor(color, visitedLinkColor));
+}
+
+PassRefPtrWillBeRawPtr<AnimatableValue> AnimatableColor::interpolateTo(const AnimatableValue* value, double fraction) const
{
const AnimatableColor* color = toAnimatableColor(value);
return create(m_color.interpolateTo(color->m_color, fraction),
m_visitedLinkColor.interpolateTo(color->m_visitedLinkColor, fraction));
}
-PassRefPtr<AnimatableValue> AnimatableColor::addWith(const AnimatableValue* value) const
+bool AnimatableColor::equalTo(const AnimatableValue* value) const
{
const AnimatableColor* color = toAnimatableColor(value);
- return create(m_color.addWith(color->m_color),
- m_visitedLinkColor.addWith(color->m_visitedLinkColor));
+ return m_color == color->m_color && m_visitedLinkColor == color->m_visitedLinkColor;
}
-bool AnimatableColor::equalTo(const AnimatableValue* value) const
+double AnimatableColor::distanceTo(const AnimatableValue* value) const
{
const AnimatableColor* color = toAnimatableColor(value);
- return m_color == color->m_color && m_visitedLinkColor == color->m_visitedLinkColor;
+ return m_color.distanceTo(color->m_color);
}
} // namespace WebCore
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimatableColor.h b/chromium/third_party/WebKit/Source/core/animation/AnimatableColor.h
index 57c8fd3cfeb..87196a0aa60 100644
--- a/chromium/third_party/WebKit/Source/core/animation/AnimatableColor.h
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimatableColor.h
@@ -42,8 +42,8 @@ public:
AnimatableColorImpl(Color);
Color toColor() const;
AnimatableColorImpl interpolateTo(const AnimatableColorImpl&, double fraction) const;
- AnimatableColorImpl addWith(const AnimatableColorImpl&) const;
bool operator==(const AnimatableColorImpl&) const;
+ double distanceTo(const AnimatableColorImpl&) const;
private:
float m_alpha;
@@ -56,15 +56,16 @@ private:
// property. Currently it is used for all properties, even those which do not
// support a separate 'visited link' color (eg SVG properties). This is correct
// but inefficient.
-class AnimatableColor : public AnimatableValue {
+class AnimatableColor FINAL : public AnimatableValue {
public:
- static PassRefPtr<AnimatableColor> create(const AnimatableColorImpl&, const AnimatableColorImpl& visitedLinkColor);
+ static PassRefPtrWillBeRawPtr<AnimatableColor> create(const AnimatableColorImpl&, const AnimatableColorImpl& visitedLinkColor);
Color color() const { return m_color.toColor(); }
Color visitedLinkColor() const { return m_visitedLinkColor.toColor(); }
+ virtual void trace(Visitor* visitor) OVERRIDE { AnimatableValue::trace(visitor); }
+
protected:
- virtual PassRefPtr<AnimatableValue> interpolateTo(const AnimatableValue*, double fraction) const OVERRIDE;
- virtual PassRefPtr<AnimatableValue> addWith(const AnimatableValue*) const OVERRIDE;
+ virtual PassRefPtrWillBeRawPtr<AnimatableValue> interpolateTo(const AnimatableValue*, double fraction) const OVERRIDE;
private:
AnimatableColor(const AnimatableColorImpl& color, const AnimatableColorImpl& visitedLinkColor)
@@ -74,6 +75,7 @@ private:
}
virtual AnimatableType type() const OVERRIDE { return TypeColor; }
virtual bool equalTo(const AnimatableValue*) const OVERRIDE;
+ virtual double distanceTo(const AnimatableValue*) const OVERRIDE;
const AnimatableColorImpl m_color;
const AnimatableColorImpl m_visitedLinkColor;
};
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimatableColorTest.cpp b/chromium/third_party/WebKit/Source/core/animation/AnimatableColorTest.cpp
index 1e6ae355430..de4de666f37 100644
--- a/chromium/third_party/WebKit/Source/core/animation/AnimatableColorTest.cpp
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimatableColorTest.cpp
@@ -40,10 +40,8 @@ namespace {
TEST(AnimationAnimatableColorTest, ToColor)
{
Color transparent = AnimatableColorImpl(Color::transparent).toColor();
- EXPECT_TRUE(transparent.isValid());
EXPECT_EQ(transparent.rgb(), Color::transparent);
Color red = AnimatableColorImpl(Color(0xFFFF0000)).toColor();
- EXPECT_TRUE(red.isValid());
EXPECT_EQ(red.rgb(), 0xFFFF0000);
}
@@ -67,15 +65,16 @@ TEST(AnimationAnimatableColorTest, Interpolate)
EXPECT_EQ(AnimatableColorImpl(Color(0x10204080)).interpolateTo(Color(0x104080C0), 0.5).toColor().rgb(), 0x103060A0u);
}
-TEST(AnimationAnimatableColorTest, Add)
+TEST(AnimationAnimatableColorTest, Distance)
{
- EXPECT_EQ(AnimatableColorImpl(Color(0xFF012345)).addWith(Color(0xFF543210)).toColor().rgb(), 0xFF555555);
- EXPECT_EQ(AnimatableColorImpl(Color(0xFF808080)).addWith(Color(0xFF808080)).toColor().rgb(), 0xFFFFFFFF);
- EXPECT_EQ(AnimatableColorImpl(Color(0x80FFFFFF)).addWith(Color(0x80FFFFFF)).toColor().rgb(), 0xFFFFFFFF);
- EXPECT_EQ(AnimatableColorImpl(Color(0x40FFFFFF)).addWith(Color(0x40FFFFFF)).toColor().rgb(), 0x80FFFFFF);
- EXPECT_EQ(AnimatableColorImpl(Color(0x40004080)).addWith(Color(0x80804000)).toColor().rgb(), 0xC055402B);
- EXPECT_EQ(AnimatableColorImpl(Color(0x10204080)).addWith(Color(0x104080C0)).toColor().rgb(), 0x203060A0u);
-}
+ EXPECT_NEAR(1.0, AnimatableColorImpl(Color(0xFF000000)).distanceTo(Color(0xFFFF0000)), 0.00000001);
+ EXPECT_NEAR(13.0 / 255, AnimatableColorImpl(Color(0xFF53647C)).distanceTo(Color(0xFF506070)), 0.00000001);
+ EXPECT_NEAR(60.0 / 255, AnimatableColorImpl(Color(0x3C000000)).distanceTo(Color(0x00FFFFFF)), 0.00000001);
+ EXPECT_NEAR(60.0 / 255, AnimatableColorImpl(Color(0x3C000000)).distanceTo(Color(0x3C00FF00)), 0.00000001);
+ RefPtrWillBeRawPtr<AnimatableColor> first = AnimatableColor::create(AnimatableColorImpl(Color(0xFF53647C)), AnimatableColorImpl(Color(0xFF000000)));
+ RefPtrWillBeRawPtr<AnimatableColor> second = AnimatableColor::create(AnimatableColorImpl(Color(0xFF506070)), AnimatableColorImpl(Color(0xFF000000)));
+ EXPECT_NEAR(13.0 / 255, AnimatableValue::distance(first.get(), second.get()), 0.00000001);
}
+}
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimatableDouble.cpp b/chromium/third_party/WebKit/Source/core/animation/AnimatableDouble.cpp
index 0e6cc0e2851..b27e515056f 100644
--- a/chromium/third_party/WebKit/Source/core/animation/AnimatableDouble.cpp
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimatableDouble.cpp
@@ -31,18 +31,18 @@
#include "config.h"
#include "core/animation/AnimatableDouble.h"
-#include "core/css/CSSPrimitiveValue.h"
-#include "core/css/CSSValuePool.h"
#include "platform/animation/AnimationUtilities.h"
+#include <math.h>
namespace WebCore {
-PassRefPtr<CSSValue> AnimatableDouble::toCSSValue() const
+bool AnimatableDouble::usesDefaultInterpolationWith(const AnimatableValue* value) const
{
- return cssValuePool().createValue(m_number, CSSPrimitiveValue::CSS_NUMBER);
+ const AnimatableDouble* other = toAnimatableDouble(value);
+ return (m_constraint == InterpolationIsNonContinuousWithZero) && (!m_number || !other->m_number);
}
-PassRefPtr<AnimatableValue> AnimatableDouble::interpolateTo(const AnimatableValue* value, double fraction) const
+PassRefPtrWillBeRawPtr<AnimatableValue> AnimatableDouble::interpolateTo(const AnimatableValue* value, double fraction) const
{
const AnimatableDouble* other = toAnimatableDouble(value);
ASSERT(m_constraint == other->m_constraint);
@@ -51,21 +51,15 @@ PassRefPtr<AnimatableValue> AnimatableDouble::interpolateTo(const AnimatableValu
return AnimatableDouble::create(blend(m_number, other->m_number, fraction));
}
-PassRefPtr<AnimatableValue> AnimatableDouble::addWith(const AnimatableValue* value) const
+bool AnimatableDouble::equalTo(const AnimatableValue* value) const
{
- // Optimization for adding with 0.
- if (!m_number)
- return takeConstRef(value);
- const AnimatableDouble* other = toAnimatableDouble(value);
- if (!other->m_number)
- return takeConstRef(this);
-
- return AnimatableDouble::create(m_number + other->m_number);
+ return m_number == toAnimatableDouble(value)->m_number;
}
-bool AnimatableDouble::equalTo(const AnimatableValue* value) const
+double AnimatableDouble::distanceTo(const AnimatableValue* value) const
{
- return m_number == toAnimatableDouble(value)->m_number;
+ const AnimatableDouble* other = toAnimatableDouble(value);
+ return fabs(m_number - other->m_number);
}
} // namespace WebCore
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimatableDouble.h b/chromium/third_party/WebKit/Source/core/animation/AnimatableDouble.h
index b2b71165a6a..88ef247c4e5 100644
--- a/chromium/third_party/WebKit/Source/core/animation/AnimatableDouble.h
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimatableDouble.h
@@ -32,11 +32,10 @@
#define AnimatableDouble_h
#include "core/animation/AnimatableValue.h"
-#include "core/css/CSSValue.h"
namespace WebCore {
-class AnimatableDouble : public AnimatableValue {
+class AnimatableDouble FINAL : public AnimatableValue {
public:
virtual ~AnimatableDouble() { }
@@ -45,17 +44,18 @@ public:
InterpolationIsNonContinuousWithZero,
};
- static PassRefPtr<AnimatableDouble> create(double number, Constraint constraint = Unconstrained)
+ static PassRefPtrWillBeRawPtr<AnimatableDouble> create(double number, Constraint constraint = Unconstrained)
{
- return adoptRef(new AnimatableDouble(number, constraint));
+ return adoptRefWillBeNoop(new AnimatableDouble(number, constraint));
}
- PassRefPtr<CSSValue> toCSSValue() const;
double toDouble() const { return m_number; }
+ virtual void trace(Visitor* visitor) OVERRIDE { AnimatableValue::trace(visitor); }
+
protected:
- virtual PassRefPtr<AnimatableValue> interpolateTo(const AnimatableValue*, double fraction) const OVERRIDE;
- virtual PassRefPtr<AnimatableValue> addWith(const AnimatableValue*) const OVERRIDE;
+ virtual PassRefPtrWillBeRawPtr<AnimatableValue> interpolateTo(const AnimatableValue*, double fraction) const OVERRIDE;
+ virtual bool usesDefaultInterpolationWith(const AnimatableValue*) const OVERRIDE;
private:
AnimatableDouble(double number, Constraint constraint)
@@ -65,6 +65,7 @@ private:
}
virtual AnimatableType type() const OVERRIDE { return TypeDouble; }
virtual bool equalTo(const AnimatableValue*) const OVERRIDE;
+ virtual double distanceTo(const AnimatableValue*) const OVERRIDE;
double m_number;
Constraint m_constraint;
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimatableDoubleTest.cpp b/chromium/third_party/WebKit/Source/core/animation/AnimatableDoubleTest.cpp
index ce8510bd544..f1948fb18b8 100644
--- a/chromium/third_party/WebKit/Source/core/animation/AnimatableDoubleTest.cpp
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimatableDoubleTest.cpp
@@ -31,8 +31,6 @@
#include "config.h"
#include "core/animation/AnimatableDouble.h"
-#include "core/css/CSSPrimitiveValue.h"
-
#include <gtest/gtest.h>
using namespace WebCore;
@@ -51,14 +49,6 @@ TEST(AnimationAnimatableDoubleTest, Equal)
EXPECT_FALSE(AnimatableDouble::create(5)->equals(AnimatableDouble::create(10).get()));
}
-TEST(AnimationAnimatableDoubleTest, ToCSSValue)
-{
- RefPtr<CSSValue> cssValue5 = CSSPrimitiveValue::create(5, CSSPrimitiveValue::CSS_NUMBER);
- RefPtr<CSSValue> cssValue10 = CSSPrimitiveValue::create(10, CSSPrimitiveValue::CSS_NUMBER);
- EXPECT_TRUE(AnimatableDouble::create(5)->toCSSValue()->equals(*cssValue5.get()));
- EXPECT_FALSE(AnimatableDouble::create(5)->toCSSValue()->equals(*cssValue10.get()));
-}
-
TEST(AnimationAnimatableDoubleTest, ToDouble)
{
EXPECT_EQ(5.9, AnimatableDouble::create(5.9)->toDouble());
@@ -68,8 +58,8 @@ TEST(AnimationAnimatableDoubleTest, ToDouble)
TEST(AnimationAnimatableDoubleTest, Interpolate)
{
- RefPtr<AnimatableDouble> from10 = AnimatableDouble::create(10);
- RefPtr<AnimatableDouble> to20 = AnimatableDouble::create(20);
+ RefPtrWillBeRawPtr<AnimatableDouble> from10 = AnimatableDouble::create(10);
+ RefPtrWillBeRawPtr<AnimatableDouble> to20 = AnimatableDouble::create(20);
EXPECT_EQ(5, toAnimatableDouble(AnimatableValue::interpolate(from10.get(), to20.get(), -0.5).get())->toDouble());
EXPECT_EQ(10, toAnimatableDouble(AnimatableValue::interpolate(from10.get(), to20.get(), 0).get())->toDouble());
EXPECT_EQ(14, toAnimatableDouble(AnimatableValue::interpolate(from10.get(), to20.get(), 0.4).get())->toDouble());
@@ -79,13 +69,15 @@ TEST(AnimationAnimatableDoubleTest, Interpolate)
EXPECT_EQ(25, toAnimatableDouble(AnimatableValue::interpolate(from10.get(), to20.get(), 1.5).get())->toDouble());
}
-TEST(AnimationAnimatableDoubleTest, Add)
+TEST(AnimationAnimatableDoubleTest, Distance)
{
- EXPECT_EQ(-10, toAnimatableDouble(AnimatableValue::add(AnimatableDouble::create(-2).get(), AnimatableDouble::create(-8).get()).get())->toDouble());
- EXPECT_EQ(0, toAnimatableDouble(AnimatableValue::add(AnimatableDouble::create(50).get(), AnimatableDouble::create(-50).get()).get())->toDouble());
- EXPECT_EQ(10, toAnimatableDouble(AnimatableValue::add(AnimatableDouble::create(4).get(), AnimatableDouble::create(6).get()).get())->toDouble());
- EXPECT_EQ(20, toAnimatableDouble(AnimatableValue::add(AnimatableDouble::create(0).get(), AnimatableDouble::create(20).get()).get())->toDouble());
- EXPECT_EQ(30, toAnimatableDouble(AnimatableValue::add(AnimatableDouble::create(30).get(), AnimatableDouble::create(0).get()).get())->toDouble());
+ RefPtrWillBeRawPtr<AnimatableDouble> first = AnimatableDouble::create(-1.5);
+ RefPtrWillBeRawPtr<AnimatableDouble> second = AnimatableDouble::create(2.25);
+ RefPtrWillBeRawPtr<AnimatableDouble> third = AnimatableDouble::create(3);
+
+ EXPECT_DOUBLE_EQ(3.75, AnimatableValue::distance(first.get(), second.get()));
+ EXPECT_DOUBLE_EQ(0.75, AnimatableValue::distance(second.get(), third.get()));
+ EXPECT_DOUBLE_EQ(4.5, AnimatableValue::distance(third.get(), first.get()));
}
}
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimatableFilterOperations.cpp b/chromium/third_party/WebKit/Source/core/animation/AnimatableFilterOperations.cpp
index 31edeabb24b..d0aebf007d4 100644
--- a/chromium/third_party/WebKit/Source/core/animation/AnimatableFilterOperations.cpp
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimatableFilterOperations.cpp
@@ -35,12 +35,18 @@
namespace WebCore {
-PassRefPtr<AnimatableValue> AnimatableFilterOperations::interpolateTo(const AnimatableValue* value, double fraction) const
+bool AnimatableFilterOperations::usesDefaultInterpolationWith(const AnimatableValue* value) const
{
const AnimatableFilterOperations* target = toAnimatableFilterOperations(value);
- if (!operations().canInterpolateWith(target->operations()))
+ return !operations().canInterpolateWith(target->operations());
+}
+
+PassRefPtrWillBeRawPtr<AnimatableValue> AnimatableFilterOperations::interpolateTo(const AnimatableValue* value, double fraction) const
+{
+ if (usesDefaultInterpolationWith(value))
return defaultInterpolateTo(this, value, fraction);
+ const AnimatableFilterOperations* target = toAnimatableFilterOperations(value);
FilterOperations result;
size_t fromSize = operations().size();
size_t toSize = target->operations().size();
@@ -57,12 +63,6 @@ PassRefPtr<AnimatableValue> AnimatableFilterOperations::interpolateTo(const Anim
return AnimatableFilterOperations::create(result);
}
-PassRefPtr<AnimatableValue> AnimatableFilterOperations::addWith(const AnimatableValue* value) const
-{
- ASSERT_WITH_MESSAGE(false, "Web Animations not yet implemented: AnimatableFilterOperations::addWith()");
- return defaultAddWith(this, value);
-}
-
bool AnimatableFilterOperations::equalTo(const AnimatableValue* value) const
{
return operations() == toAnimatableFilterOperations(value)->operations();
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimatableFilterOperations.h b/chromium/third_party/WebKit/Source/core/animation/AnimatableFilterOperations.h
index 17c694474ce..e047201652f 100644
--- a/chromium/third_party/WebKit/Source/core/animation/AnimatableFilterOperations.h
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimatableFilterOperations.h
@@ -36,18 +36,20 @@
namespace WebCore {
-class AnimatableFilterOperations : public AnimatableValue {
+class AnimatableFilterOperations FINAL : public AnimatableValue {
public:
virtual ~AnimatableFilterOperations() { }
- static PassRefPtr<AnimatableFilterOperations> create(const FilterOperations& operations)
+ static PassRefPtrWillBeRawPtr<AnimatableFilterOperations> create(const FilterOperations& operations)
{
- return adoptRef(new AnimatableFilterOperations(operations));
+ return adoptRefWillBeNoop(new AnimatableFilterOperations(operations));
}
const FilterOperations& operations() const { return m_operations; }
+ virtual void trace(Visitor* visitor) OVERRIDE { AnimatableValue::trace(visitor); }
+
protected:
- virtual PassRefPtr<AnimatableValue> interpolateTo(const AnimatableValue*, double fraction) const OVERRIDE;
- virtual PassRefPtr<AnimatableValue> addWith(const AnimatableValue*) const OVERRIDE;
+ virtual PassRefPtrWillBeRawPtr<AnimatableValue> interpolateTo(const AnimatableValue*, double fraction) const OVERRIDE;
+ virtual bool usesDefaultInterpolationWith(const AnimatableValue*) const OVERRIDE;
private:
AnimatableFilterOperations(const FilterOperations& operations)
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimatableImage.cpp b/chromium/third_party/WebKit/Source/core/animation/AnimatableImage.cpp
index eee86c39987..a347e82696f 100644
--- a/chromium/third_party/WebKit/Source/core/animation/AnimatableImage.cpp
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimatableImage.cpp
@@ -37,45 +37,32 @@
namespace WebCore {
-PassRefPtr<AnimatableValue> AnimatableImage::interpolateTo(const AnimatableValue* value, double fraction) const
+// FIXME: Once cross-fade works on generated image types, remove this method.
+bool AnimatableImage::usesDefaultInterpolationWith(const AnimatableValue* value) const
{
- if (fraction <= 0 || fraction >= 1)
- return defaultInterpolateTo(this, value, fraction);
- RefPtr<CSSValue> fromValue = this->toCSSValue();
- // FIXME: Once cross-fade works on generated image types, remove this check.
- if (fromValue->isImageGeneratorValue())
- return defaultInterpolateTo(this, value, fraction);
- if (!fromValue->isImageValue() && !fromValue->isImageGeneratorValue()) {
- if (!m_image->isImageResource())
- return defaultInterpolateTo(this, value, fraction);
- ImageResource* resource = static_cast<ImageResource*>(m_image->data());
- fromValue = CSSImageValue::create(resource->url(), m_image.get());
- }
- const AnimatableImage* image = toAnimatableImage(value);
- RefPtr<CSSValue> toValue = image->toCSSValue();
- // FIXME: Once cross-fade works on generated image types, remove this check.
- if (toValue->isImageGeneratorValue())
- return defaultInterpolateTo(this, value, fraction);
- if (!toValue->isImageValue() && !toValue->isImageGeneratorValue()) {
- if (!image->m_image->isImageResource())
- return defaultInterpolateTo(this, value, fraction);
- ImageResource* resource = static_cast<ImageResource*>(image->m_image->data());
- toValue = CSSImageValue::create(resource->url(), image->m_image.get());
- }
- RefPtr<CSSCrossfadeValue> crossfadeValue = CSSCrossfadeValue::create(fromValue, toValue);
- crossfadeValue->setPercentage(CSSPrimitiveValue::create(fraction, CSSPrimitiveValue::CSS_NUMBER));
- return create(StyleGeneratedImage::create(crossfadeValue.get()).get());
+ if (!m_value->isImageValue())
+ return true;
+ if (!toAnimatableImage(value)->toCSSValue()->isImageValue())
+ return true;
+ return false;
}
-PassRefPtr<AnimatableValue> AnimatableImage::addWith(const AnimatableValue* value) const
+PassRefPtrWillBeRawPtr<AnimatableValue> AnimatableImage::interpolateTo(const AnimatableValue* value, double fraction) const
{
- // FIXME: Correct procedure is defined here: http://dev.w3.org/fxtf/web-animations/#the--image--type
- return defaultAddWith(this, value);
+ if (fraction <= 0 || fraction >= 1 || usesDefaultInterpolationWith(value))
+ return defaultInterpolateTo(this, value, fraction);
+
+ CSSValue* fromValue = toCSSValue();
+ CSSValue* toValue = toAnimatableImage(value)->toCSSValue();
+
+ RefPtrWillBeRawPtr<CSSCrossfadeValue> crossfadeValue = CSSCrossfadeValue::create(fromValue, toValue);
+ crossfadeValue->setPercentage(CSSPrimitiveValue::create(fraction, CSSPrimitiveValue::CSS_NUMBER));
+ return create(crossfadeValue);
}
bool AnimatableImage::equalTo(const AnimatableValue* value) const
{
- return StyleImage::imagesEquivalent(m_image.get(), toAnimatableImage(value)->m_image.get());
+ return m_value->equals(*toAnimatableImage(value)->m_value.get());
}
}
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimatableImage.h b/chromium/third_party/WebKit/Source/core/animation/AnimatableImage.h
index 40152f95c5e..e76b6196e8c 100644
--- a/chromium/third_party/WebKit/Source/core/animation/AnimatableImage.h
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimatableImage.h
@@ -37,30 +37,35 @@
namespace WebCore {
-class AnimatableImage : public AnimatableValue {
+class AnimatableImage FINAL : public AnimatableValue {
public:
virtual ~AnimatableImage() { }
- static PassRefPtr<AnimatableImage> create(StyleImage* image)
+ static PassRefPtrWillBeRawPtr<AnimatableImage> create(PassRefPtrWillBeRawPtr<CSSValue> value)
{
- return adoptRef(new AnimatableImage(image));
+ return adoptRefWillBeNoop(new AnimatableImage(value));
+ }
+ CSSValue* toCSSValue() const { return m_value.get(); }
+
+ virtual void trace(Visitor* visitor) OVERRIDE
+ {
+ visitor->trace(m_value);
+ AnimatableValue::trace(visitor);
}
- PassRefPtr<CSSValue> toCSSValue() const { return m_image->cssValue(); }
- StyleImage* toStyleImage() const { return m_image.get(); }
protected:
- virtual PassRefPtr<AnimatableValue> interpolateTo(const AnimatableValue*, double fraction) const OVERRIDE;
- virtual PassRefPtr<AnimatableValue> addWith(const AnimatableValue*) const OVERRIDE;
+ virtual PassRefPtrWillBeRawPtr<AnimatableValue> interpolateTo(const AnimatableValue*, double fraction) const OVERRIDE;
+ virtual bool usesDefaultInterpolationWith(const AnimatableValue*) const OVERRIDE;
private:
- AnimatableImage(StyleImage* image)
- : m_image(image)
+ AnimatableImage(PassRefPtrWillBeRawPtr<CSSValue> value)
+ : m_value(value)
{
- ASSERT(m_image);
+ ASSERT(m_value.get());
}
virtual AnimatableType type() const OVERRIDE { return TypeImage; }
virtual bool equalTo(const AnimatableValue*) const OVERRIDE;
- const RefPtr<StyleImage> m_image;
+ const RefPtrWillBeMember<CSSValue> m_value;
};
DEFINE_ANIMATABLE_VALUE_TYPE_CASTS(AnimatableImage, isImage());
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimatableLength.cpp b/chromium/third_party/WebKit/Source/core/animation/AnimatableLength.cpp
index 38a46590dbb..c167c20a752 100644
--- a/chromium/third_party/WebKit/Source/core/animation/AnimatableLength.cpp
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimatableLength.cpp
@@ -31,211 +31,53 @@
#include "config.h"
#include "core/animation/AnimatableLength.h"
-#include "core/css/CSSPrimitiveValueMappings.h"
#include "platform/CalculationValue.h"
#include "platform/animation/AnimationUtilities.h"
namespace WebCore {
-PassRefPtr<AnimatableLength> AnimatableLength::create(CSSValue* value)
-{
- ASSERT(canCreateFrom(value));
- if (value->isPrimitiveValue()) {
- CSSPrimitiveValue* primitiveValue = WebCore::toCSSPrimitiveValue(value);
- const CSSCalcValue* calcValue = primitiveValue->cssCalcValue();
- if (calcValue)
- return create(calcValue->expressionNode(), primitiveValue);
- NumberUnitType unitType;
- bool isPrimitiveLength = primitiveUnitToNumberType(primitiveValue->primitiveType(), unitType);
- ASSERT_UNUSED(isPrimitiveLength, isPrimitiveLength);
- const double scale = CSSPrimitiveValue::conversionToCanonicalUnitsScaleFactor(primitiveValue->primitiveType());
- return create(primitiveValue->getDoubleValue() * scale, unitType, primitiveValue);
- }
-
- if (value->isCalcValue())
- return create(toCSSCalcValue(value)->expressionNode());
-
- ASSERT_NOT_REACHED();
- return 0;
-}
+namespace {
-bool AnimatableLength::canCreateFrom(const CSSValue* value)
+double clampNumber(double value, ValueRange range)
{
- ASSERT(value);
- if (value->isPrimitiveValue()) {
- const CSSPrimitiveValue* primitiveValue = WebCore::toCSSPrimitiveValue(value);
- if (primitiveValue->cssCalcValue())
- return true;
-
- NumberUnitType unitType;
- // Only returns true if the type is a primitive length unit.
- return primitiveUnitToNumberType(primitiveValue->primitiveType(), unitType);
- }
- return value->isCalcValue();
+ if (range == ValueRangeNonNegative)
+ return std::max(value, 0.0);
+ ASSERT(range == ValueRangeAll);
+ return value;
}
-PassRefPtr<CSSValue> AnimatableLength::toCSSValue(NumberRange range) const
-{
- return toCSSPrimitiveValue(range);
-}
+} // namespace
-Length AnimatableLength::toLength(const CSSToLengthConversionData& conversionData, NumberRange range) const
+AnimatableLength::AnimatableLength(const Length& length, float zoom)
{
- // Avoid creating a CSSValue in the common cases
- if (m_unitType == UnitTypePixels)
- return Length(clampedNumber(range) * conversionData.zoom(), Fixed);
- if (m_unitType == UnitTypePercentage)
- return Length(clampedNumber(range), Percent);
-
- return toCSSPrimitiveValue(range)->convertToLength<AnyConversion>(conversionData);
+ ASSERT(zoom);
+ PixelsAndPercent pixelsAndPercent = length.pixelsAndPercent();
+ m_pixels = pixelsAndPercent.pixels / zoom;
+ m_percent = pixelsAndPercent.percent;
+ m_hasPixels = length.type() != Percent;
+ m_hasPercent = !length.isFixed();
}
-PassRefPtr<AnimatableValue> AnimatableLength::interpolateTo(const AnimatableValue* value, double fraction) const
+Length AnimatableLength::length(float zoom, ValueRange range) const
{
- const AnimatableLength* length = toAnimatableLength(value);
- NumberUnitType type = commonUnitType(length);
- if (type != UnitTypeCalc)
- return AnimatableLength::create(blend(m_number, length->m_number, fraction), type);
-
- // FIXME(crbug.com/168840): Support for viewport units in calc needs to be added before we can blend them with other units.
- if (isViewportUnit() || length->isViewportUnit())
- return defaultInterpolateTo(this, value, fraction);
-
- return AnimatableLength::create(scale(1 - fraction).get(), length->scale(fraction).get());
+ if (!m_hasPercent)
+ return Length(clampNumber(m_pixels, range) * zoom, Fixed);
+ if (!m_hasPixels)
+ return Length(clampNumber(m_percent, range), Percent);
+ return Length(CalculationValue::create(PixelsAndPercent(m_pixels * zoom, m_percent), range));
}
-PassRefPtr<AnimatableValue> AnimatableLength::addWith(const AnimatableValue* value) const
+PassRefPtrWillBeRawPtr<AnimatableValue> AnimatableLength::interpolateTo(const AnimatableValue* value, double fraction) const
{
- // Optimization for adding with 0.
- if (isUnitlessZero())
- return takeConstRef(value);
-
const AnimatableLength* length = toAnimatableLength(value);
- if (length->isUnitlessZero())
- return takeConstRef(this);
-
- NumberUnitType type = commonUnitType(length);
- if (type != UnitTypeCalc)
- return AnimatableLength::create(m_number + length->m_number, type);
-
- return AnimatableLength::create(this, length);
+ return create(blend(m_pixels, length->m_pixels, fraction), blend(m_percent, length->m_percent, fraction),
+ m_hasPixels || length->m_hasPixels, m_hasPercent || length->m_hasPercent);
}
bool AnimatableLength::equalTo(const AnimatableValue* value) const
{
const AnimatableLength* length = toAnimatableLength(value);
- if (m_unitType != length->m_unitType)
- return false;
- if (isCalc())
- return m_calcExpression == length->m_calcExpression || m_calcExpression->equals(*length->m_calcExpression);
- return m_number == length->m_number;
-}
-
-PassRefPtr<CSSCalcExpressionNode> AnimatableLength::toCSSCalcExpressionNode() const
-{
- if (isCalc())
- return m_calcExpression;
- return CSSCalcValue::createExpressionNode(toCSSPrimitiveValue(AllValues), m_number == trunc(m_number));
-}
-
-static bool isCompatibleWithRange(const CSSPrimitiveValue* primitiveValue, NumberRange range)
-{
- ASSERT(primitiveValue);
- if (range == AllValues)
- return true;
- if (primitiveValue->isCalculated())
- return primitiveValue->cssCalcValue()->permittedValueRange() == ValueRangeNonNegative;
- return primitiveValue->getDoubleValue() >= 0;
-}
-
-PassRefPtr<CSSPrimitiveValue> AnimatableLength::toCSSPrimitiveValue(NumberRange range) const
-{
- if (!m_cachedCSSPrimitiveValue || !isCompatibleWithRange(m_cachedCSSPrimitiveValue.get(), range)) {
- if (isCalc())
- m_cachedCSSPrimitiveValue = CSSPrimitiveValue::create(CSSCalcValue::create(m_calcExpression, range == AllValues ? ValueRangeAll : ValueRangeNonNegative));
- else
- m_cachedCSSPrimitiveValue = CSSPrimitiveValue::create(clampedNumber(range), static_cast<CSSPrimitiveValue::UnitTypes>(numberTypeToPrimitiveUnit(m_unitType)));
- }
- return m_cachedCSSPrimitiveValue;
-}
-
-PassRefPtr<AnimatableLength> AnimatableLength::scale(double factor) const
-{
- if (isCalc()) {
- return AnimatableLength::create(CSSCalcValue::createExpressionNode(
- m_calcExpression,
- CSSCalcValue::createExpressionNode(CSSPrimitiveValue::create(factor, CSSPrimitiveValue::CSS_NUMBER)),
- CalcMultiply));
- }
- return AnimatableLength::create(m_number * factor, m_unitType);
-}
-
-bool AnimatableLength::primitiveUnitToNumberType(unsigned short primitiveUnit, NumberUnitType& numberType)
-{
- switch (primitiveUnit) {
- case CSSPrimitiveValue::CSS_PX:
- case CSSPrimitiveValue::CSS_CM:
- case CSSPrimitiveValue::CSS_MM:
- case CSSPrimitiveValue::CSS_IN:
- case CSSPrimitiveValue::CSS_PT:
- case CSSPrimitiveValue::CSS_PC:
- numberType = UnitTypePixels;
- return true;
- case CSSPrimitiveValue::CSS_EMS:
- numberType = UnitTypeFontSize;
- return true;
- case CSSPrimitiveValue::CSS_EXS:
- numberType = UnitTypeFontXSize;
- return true;
- case CSSPrimitiveValue::CSS_REMS:
- numberType = UnitTypeRootFontSize;
- return true;
- case CSSPrimitiveValue::CSS_PERCENTAGE:
- numberType = UnitTypePercentage;
- return true;
- case CSSPrimitiveValue::CSS_VW:
- numberType = UnitTypeViewportWidth;
- return true;
- case CSSPrimitiveValue::CSS_VH:
- numberType = UnitTypeViewportHeight;
- return true;
- case CSSPrimitiveValue::CSS_VMIN:
- numberType = UnitTypeViewportMin;
- return true;
- case CSSPrimitiveValue::CSS_VMAX:
- numberType = UnitTypeViewportMax;
- return true;
- default:
- return false;
- }
-}
-
-unsigned short AnimatableLength::numberTypeToPrimitiveUnit(NumberUnitType numberType)
-{
- switch (numberType) {
- case UnitTypePixels:
- return CSSPrimitiveValue::CSS_PX;
- case UnitTypeFontSize:
- return CSSPrimitiveValue::CSS_EMS;
- case UnitTypeFontXSize:
- return CSSPrimitiveValue::CSS_EXS;
- case UnitTypeRootFontSize:
- return CSSPrimitiveValue::CSS_REMS;
- case UnitTypePercentage:
- return CSSPrimitiveValue::CSS_PERCENTAGE;
- case UnitTypeViewportWidth:
- return CSSPrimitiveValue::CSS_VW;
- case UnitTypeViewportHeight:
- return CSSPrimitiveValue::CSS_VH;
- case UnitTypeViewportMin:
- return CSSPrimitiveValue::CSS_VMIN;
- case UnitTypeViewportMax:
- return CSSPrimitiveValue::CSS_VMAX;
- case UnitTypeCalc:
- return CSSPrimitiveValue::CSS_UNKNOWN;
- }
- ASSERT_NOT_REACHED();
- return CSSPrimitiveValue::CSS_UNKNOWN;
+ return m_pixels == length->m_pixels && m_percent == length->m_percent && m_hasPixels == length->m_hasPixels && m_hasPercent == length->m_hasPercent;
}
} // namespace WebCore
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimatableLength.h b/chromium/third_party/WebKit/Source/core/animation/AnimatableLength.h
index 14745761248..754c0436230 100644
--- a/chromium/third_party/WebKit/Source/core/animation/AnimatableLength.h
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimatableLength.h
@@ -32,131 +32,44 @@
#define AnimatableLength_h
#include "core/animation/AnimatableValue.h"
-#include "core/css/CSSCalculationValue.h"
-#include "core/css/CSSPrimitiveValue.h"
#include "platform/Length.h"
namespace WebCore {
-enum NumberRange {
- AllValues,
- NonNegativeValues,
-};
-
-// Handles animation of CSS length and percentage values including CSS calc.
-// See primitiveUnitToNumberType() for the list of supported units.
-// If created from a CSSPrimitiveValue this class will cache it to be returned in toCSSValue().
-class AnimatableLength : public AnimatableValue {
+class AnimatableLength FINAL : public AnimatableValue {
public:
- enum NumberUnitType {
- UnitTypeCalc,
- UnitTypePixels,
- UnitTypePercentage,
- UnitTypeFontSize,
- UnitTypeFontXSize,
- UnitTypeRootFontSize,
- UnitTypeViewportWidth,
- UnitTypeViewportHeight,
- UnitTypeViewportMin,
- UnitTypeViewportMax,
- };
-
- virtual ~AnimatableLength() { }
- static bool canCreateFrom(const CSSValue*);
- static PassRefPtr<AnimatableLength> create(CSSValue*);
- static PassRefPtr<AnimatableLength> create(double number, NumberUnitType unitType, CSSPrimitiveValue* cssPrimitiveValue = 0)
- {
- return adoptRef(new AnimatableLength(number, unitType, cssPrimitiveValue));
- }
- static PassRefPtr<AnimatableLength> create(PassRefPtr<CSSCalcExpressionNode> calcExpression, CSSPrimitiveValue* cssPrimitiveValue = 0)
+ static PassRefPtrWillBeRawPtr<AnimatableLength> create(const Length& length, float zoom)
{
- return adoptRef(new AnimatableLength(calcExpression, cssPrimitiveValue));
+ return adoptRefWillBeNoop(new AnimatableLength(length, zoom));
}
- PassRefPtr<CSSValue> toCSSValue(NumberRange = AllValues) const;
- Length toLength(const CSSToLengthConversionData&, NumberRange = AllValues) const;
+ Length length(float zoom, ValueRange) const;
protected:
- virtual PassRefPtr<AnimatableValue> interpolateTo(const AnimatableValue*, double fraction) const OVERRIDE;
- virtual PassRefPtr<AnimatableValue> addWith(const AnimatableValue*) const OVERRIDE;
+ virtual PassRefPtrWillBeRawPtr<AnimatableValue> interpolateTo(const AnimatableValue*, double fraction) const OVERRIDE;
private:
- AnimatableLength(double number, NumberUnitType unitType, CSSPrimitiveValue* cssPrimitiveValue)
- : m_number(number)
- , m_unitType(unitType)
- , m_cachedCSSPrimitiveValue(cssPrimitiveValue)
+ static PassRefPtrWillBeRawPtr<AnimatableLength> create(double pixels, double percent, bool hasPixels, bool hasPercent)
{
- ASSERT(m_unitType != UnitTypeCalc);
+ return adoptRefWillBeNoop(new AnimatableLength(pixels, percent, hasPixels, hasPercent));
}
- AnimatableLength(PassRefPtr<CSSCalcExpressionNode> calcExpression, CSSPrimitiveValue* cssPrimitiveValue)
- : m_unitType(UnitTypeCalc)
- , m_calcExpression(calcExpression)
- , m_cachedCSSPrimitiveValue(cssPrimitiveValue)
+ AnimatableLength(const Length&, float zoom);
+ AnimatableLength(double pixels, double percent, bool hasPixels, bool hasPercent)
+ : m_pixels(pixels)
+ , m_percent(percent)
+ , m_hasPixels(hasPixels)
+ , m_hasPercent(hasPercent)
{
- ASSERT(m_calcExpression);
+ ASSERT(m_hasPixels || m_hasPercent);
}
virtual AnimatableType type() const OVERRIDE { return TypeLength; }
virtual bool equalTo(const AnimatableValue*) const OVERRIDE;
- bool isCalc() const
- {
- return m_unitType == UnitTypeCalc;
- }
-
- bool isViewportUnit() const
- {
- return m_unitType == UnitTypeViewportWidth || m_unitType == UnitTypeViewportHeight || m_unitType == UnitTypeViewportMin || m_unitType == UnitTypeViewportMax;
- }
-
- static PassRefPtr<AnimatableLength> create(const AnimatableLength* leftAddend, const AnimatableLength* rightAddend)
- {
- ASSERT(leftAddend && rightAddend);
- return create(CSSCalcValue::createExpressionNode(leftAddend->toCSSCalcExpressionNode(), rightAddend->toCSSCalcExpressionNode(), CalcAdd));
- }
-
- PassRefPtr<CSSPrimitiveValue> toCSSPrimitiveValue(NumberRange) const;
- PassRefPtr<CSSCalcExpressionNode> toCSSCalcExpressionNode() const;
-
- PassRefPtr<AnimatableLength> scale(double) const;
- double clampedNumber(NumberRange range) const
- {
- ASSERT(!isCalc());
- return (range == NonNegativeValues && m_number <= 0) ? 0 : m_number;
- }
-
- // Returns true and populates numberType, if primitiveUnit is a primitive length unit. Otherwise, returns false.
- static bool primitiveUnitToNumberType(unsigned short primitiveUnit, NumberUnitType& numberType);
-
- static unsigned short numberTypeToPrimitiveUnit(NumberUnitType numberType);
-
- // Zero is effectively unitless, except in the case of percentage.
- // http://www.w3.org/TR/css3-values/#calc-computed-value
- // e.g. calc(100% - 100% + 1em) resolves to calc(0% + 1em), not to calc(1em)
- bool isUnitlessZero() const
- {
- return !isCalc() && !m_number && m_unitType != UnitTypePercentage;
- }
-
- NumberUnitType commonUnitType(const AnimatableLength* length) const
- {
- if (m_unitType == length->m_unitType)
- return m_unitType;
-
- if (isUnitlessZero())
- return length->m_unitType;
- if (length->isUnitlessZero())
- return m_unitType;
-
- return UnitTypeCalc;
- }
-
- double m_number;
- const NumberUnitType m_unitType;
-
- RefPtr<CSSCalcExpressionNode> m_calcExpression;
-
- mutable RefPtr<CSSPrimitiveValue> m_cachedCSSPrimitiveValue;
+ virtual void trace(Visitor* visitor) OVERRIDE { AnimatableValue::trace(visitor); }
- friend class AnimationAnimatableLengthTest;
+ double m_pixels;
+ double m_percent;
+ bool m_hasPixels;
+ bool m_hasPercent;
};
DEFINE_ANIMATABLE_VALUE_TYPE_CASTS(AnimatableLength, isLength());
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimatableLengthBox.cpp b/chromium/third_party/WebKit/Source/core/animation/AnimatableLengthBox.cpp
index 825a1351655..25896210c9e 100644
--- a/chromium/third_party/WebKit/Source/core/animation/AnimatableLengthBox.cpp
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimatableLengthBox.cpp
@@ -33,7 +33,7 @@
namespace WebCore {
-PassRefPtr<AnimatableValue> AnimatableLengthBox::interpolateTo(const AnimatableValue* value, double fraction) const
+PassRefPtrWillBeRawPtr<AnimatableValue> AnimatableLengthBox::interpolateTo(const AnimatableValue* value, double fraction) const
{
const AnimatableLengthBox* lengthBox = toAnimatableLengthBox(value);
return AnimatableLengthBox::create(
@@ -43,16 +43,6 @@ PassRefPtr<AnimatableValue> AnimatableLengthBox::interpolateTo(const AnimatableV
AnimatableValue::interpolate(this->bottom(), lengthBox->bottom(), fraction));
}
-PassRefPtr<AnimatableValue> AnimatableLengthBox::addWith(const AnimatableValue* value) const
-{
- const AnimatableLengthBox* lengthBox = toAnimatableLengthBox(value);
- return AnimatableLengthBox::create(
- AnimatableValue::add(this->left(), lengthBox->left()),
- AnimatableValue::add(this->right(), lengthBox->right()),
- AnimatableValue::add(this->top(), lengthBox->top()),
- AnimatableValue::add(this->bottom(), lengthBox->bottom()));
-}
-
bool AnimatableLengthBox::equalTo(const AnimatableValue* value) const
{
const AnimatableLengthBox* lengthBox = toAnimatableLengthBox(value);
@@ -62,4 +52,13 @@ bool AnimatableLengthBox::equalTo(const AnimatableValue* value) const
&& bottom()->equals(lengthBox->bottom());
}
+void AnimatableLengthBox::trace(Visitor* visitor)
+{
+ visitor->trace(m_left);
+ visitor->trace(m_right);
+ visitor->trace(m_top);
+ visitor->trace(m_bottom);
+ AnimatableValue::trace(visitor);
+}
+
}
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimatableLengthBox.h b/chromium/third_party/WebKit/Source/core/animation/AnimatableLengthBox.h
index b7ea5be5f6a..f796e753bc3 100644
--- a/chromium/third_party/WebKit/Source/core/animation/AnimatableLengthBox.h
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimatableLengthBox.h
@@ -35,24 +35,25 @@
namespace WebCore {
-class AnimatableLengthBox : public AnimatableValue {
+class AnimatableLengthBox FINAL : public AnimatableValue {
public:
virtual ~AnimatableLengthBox() { }
- static PassRefPtr<AnimatableLengthBox> create(PassRefPtr<AnimatableValue> left, PassRefPtr<AnimatableValue> right, PassRefPtr<AnimatableValue> top, PassRefPtr<AnimatableValue> bottom)
+ static PassRefPtrWillBeRawPtr<AnimatableLengthBox> create(PassRefPtrWillBeRawPtr<AnimatableValue> left, PassRefPtrWillBeRawPtr<AnimatableValue> right, PassRefPtrWillBeRawPtr<AnimatableValue> top, PassRefPtrWillBeRawPtr<AnimatableValue> bottom)
{
- return adoptRef(new AnimatableLengthBox(left, right, top, bottom));
+ return adoptRefWillBeNoop(new AnimatableLengthBox(left, right, top, bottom));
}
const AnimatableValue* left() const { return m_left.get(); }
const AnimatableValue* right() const { return m_right.get(); }
const AnimatableValue* top() const { return m_top.get(); }
const AnimatableValue* bottom() const { return m_bottom.get(); }
+ virtual void trace(Visitor*) OVERRIDE;
+
protected:
- virtual PassRefPtr<AnimatableValue> interpolateTo(const AnimatableValue*, double fraction) const OVERRIDE;
- virtual PassRefPtr<AnimatableValue> addWith(const AnimatableValue*) const OVERRIDE;
+ virtual PassRefPtrWillBeRawPtr<AnimatableValue> interpolateTo(const AnimatableValue*, double fraction) const OVERRIDE;
private:
- AnimatableLengthBox(PassRefPtr<AnimatableValue> left, PassRefPtr<AnimatableValue> right, PassRefPtr<AnimatableValue> top, PassRefPtr<AnimatableValue> bottom)
+ AnimatableLengthBox(PassRefPtrWillBeRawPtr<AnimatableValue> left, PassRefPtrWillBeRawPtr<AnimatableValue> right, PassRefPtrWillBeRawPtr<AnimatableValue> top, PassRefPtrWillBeRawPtr<AnimatableValue> bottom)
: m_left(left)
, m_right(right)
, m_top(top)
@@ -62,10 +63,10 @@ private:
virtual AnimatableType type() const OVERRIDE { return TypeLengthBox; }
virtual bool equalTo(const AnimatableValue*) const OVERRIDE;
- RefPtr<AnimatableValue> m_left;
- RefPtr<AnimatableValue> m_right;
- RefPtr<AnimatableValue> m_top;
- RefPtr<AnimatableValue> m_bottom;
+ RefPtrWillBeMember<AnimatableValue> m_left;
+ RefPtrWillBeMember<AnimatableValue> m_right;
+ RefPtrWillBeMember<AnimatableValue> m_top;
+ RefPtrWillBeMember<AnimatableValue> m_bottom;
};
DEFINE_ANIMATABLE_VALUE_TYPE_CASTS(AnimatableLengthBox, isLengthBox());
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimatableLengthBoxAndBool.cpp b/chromium/third_party/WebKit/Source/core/animation/AnimatableLengthBoxAndBool.cpp
index da92ac24181..c598ec435a9 100644
--- a/chromium/third_party/WebKit/Source/core/animation/AnimatableLengthBoxAndBool.cpp
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimatableLengthBoxAndBool.cpp
@@ -33,26 +33,23 @@
namespace WebCore {
-PassRefPtr<AnimatableValue> AnimatableLengthBoxAndBool::interpolateTo(const AnimatableValue* value, double fraction) const
+bool AnimatableLengthBoxAndBool::usesDefaultInterpolationWith(const AnimatableValue* value) const
{
const AnimatableLengthBoxAndBool* lengthBox = toAnimatableLengthBoxAndBool(value);
- if (lengthBox->flag() == flag()) {
- return AnimatableLengthBoxAndBool::create(
- AnimatableValue::interpolate(box(), lengthBox->box(), fraction),
- flag());
- }
- return defaultInterpolateTo(this, value, fraction);
+ if (lengthBox->flag() != flag())
+ return true;
+ return AnimatableValue::usesDefaultInterpolation(lengthBox->box(), box());
}
-PassRefPtr<AnimatableValue> AnimatableLengthBoxAndBool::addWith(const AnimatableValue* value) const
+PassRefPtrWillBeRawPtr<AnimatableValue> AnimatableLengthBoxAndBool::interpolateTo(const AnimatableValue* value, double fraction) const
{
const AnimatableLengthBoxAndBool* lengthBox = toAnimatableLengthBoxAndBool(value);
if (lengthBox->flag() == flag()) {
return AnimatableLengthBoxAndBool::create(
- AnimatableValue::add(box(), lengthBox->box()),
+ AnimatableValue::interpolate(box(), lengthBox->box(), fraction),
flag());
}
- return defaultAddWith(this, value);
+ return defaultInterpolateTo(this, value, fraction);
}
bool AnimatableLengthBoxAndBool::equalTo(const AnimatableValue* value) const
@@ -61,4 +58,10 @@ bool AnimatableLengthBoxAndBool::equalTo(const AnimatableValue* value) const
return box()->equals(lengthBox->box()) && flag() == lengthBox->flag();
}
+void AnimatableLengthBoxAndBool::trace(Visitor* visitor)
+{
+ visitor->trace(m_box);
+ AnimatableValue::trace(visitor);
+}
+
}
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimatableLengthBoxAndBool.h b/chromium/third_party/WebKit/Source/core/animation/AnimatableLengthBoxAndBool.h
index 9e3379791fd..76bd94c097e 100644
--- a/chromium/third_party/WebKit/Source/core/animation/AnimatableLengthBoxAndBool.h
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimatableLengthBoxAndBool.h
@@ -35,22 +35,24 @@
namespace WebCore {
-class AnimatableLengthBoxAndBool : public AnimatableValue {
+class AnimatableLengthBoxAndBool FINAL : public AnimatableValue {
public:
virtual ~AnimatableLengthBoxAndBool() { }
- static PassRefPtr<AnimatableLengthBoxAndBool> create(PassRefPtr<AnimatableValue> box, bool flag)
+ static PassRefPtrWillBeRawPtr<AnimatableLengthBoxAndBool> create(PassRefPtrWillBeRawPtr<AnimatableValue> box, bool flag)
{
- return adoptRef(new AnimatableLengthBoxAndBool(box, flag));
+ return adoptRefWillBeNoop(new AnimatableLengthBoxAndBool(box, flag));
}
const AnimatableValue* box() const { return m_box.get(); }
bool flag() const { return m_flag; }
+ virtual void trace(Visitor*) OVERRIDE;
+
protected:
- virtual PassRefPtr<AnimatableValue> interpolateTo(const AnimatableValue*, double fraction) const OVERRIDE;
- virtual PassRefPtr<AnimatableValue> addWith(const AnimatableValue*) const OVERRIDE;
+ virtual PassRefPtrWillBeRawPtr<AnimatableValue> interpolateTo(const AnimatableValue*, double fraction) const OVERRIDE;
+ virtual bool usesDefaultInterpolationWith(const AnimatableValue*) const OVERRIDE;
private:
- AnimatableLengthBoxAndBool(PassRefPtr<AnimatableValue> box, bool flag)
+ AnimatableLengthBoxAndBool(PassRefPtrWillBeRawPtr<AnimatableValue> box, bool flag)
: m_box(box)
, m_flag(flag)
{
@@ -58,7 +60,7 @@ private:
virtual AnimatableType type() const OVERRIDE { return TypeLengthBoxAndBool; }
virtual bool equalTo(const AnimatableValue*) const OVERRIDE;
- RefPtr<AnimatableValue> m_box;
+ RefPtrWillBeMember<AnimatableValue> m_box;
bool m_flag;
};
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimatableLengthPoint.cpp b/chromium/third_party/WebKit/Source/core/animation/AnimatableLengthPoint.cpp
index e779699d93d..b8805d05685 100644
--- a/chromium/third_party/WebKit/Source/core/animation/AnimatableLengthPoint.cpp
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimatableLengthPoint.cpp
@@ -33,7 +33,7 @@
namespace WebCore {
-PassRefPtr<AnimatableValue> AnimatableLengthPoint::interpolateTo(const AnimatableValue* value, double fraction) const
+PassRefPtrWillBeRawPtr<AnimatableValue> AnimatableLengthPoint::interpolateTo(const AnimatableValue* value, double fraction) const
{
const AnimatableLengthPoint* lengthPoint = toAnimatableLengthPoint(value);
return AnimatableLengthPoint::create(
@@ -41,18 +41,17 @@ PassRefPtr<AnimatableValue> AnimatableLengthPoint::interpolateTo(const Animatabl
AnimatableValue::interpolate(this->y(), lengthPoint->y(), fraction));
}
-PassRefPtr<AnimatableValue> AnimatableLengthPoint::addWith(const AnimatableValue* value) const
+bool AnimatableLengthPoint::equalTo(const AnimatableValue* value) const
{
const AnimatableLengthPoint* lengthPoint = toAnimatableLengthPoint(value);
- return AnimatableLengthPoint::create(
- AnimatableValue::add(this->x(), lengthPoint->x()),
- AnimatableValue::add(this->y(), lengthPoint->y()));
+ return x()->equals(lengthPoint->x()) && y()->equals(lengthPoint->y());
}
-bool AnimatableLengthPoint::equalTo(const AnimatableValue* value) const
+void AnimatableLengthPoint::trace(Visitor* visitor)
{
- const AnimatableLengthPoint* lengthPoint = toAnimatableLengthPoint(value);
- return x()->equals(lengthPoint->x()) && y()->equals(lengthPoint->y());
+ visitor->trace(m_x);
+ visitor->trace(m_y);
+ AnimatableValue::trace(visitor);
}
}
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimatableLengthPoint.h b/chromium/third_party/WebKit/Source/core/animation/AnimatableLengthPoint.h
index 60b3e03f152..f2f479b11ef 100644
--- a/chromium/third_party/WebKit/Source/core/animation/AnimatableLengthPoint.h
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimatableLengthPoint.h
@@ -35,22 +35,23 @@
namespace WebCore {
-class AnimatableLengthPoint : public AnimatableValue {
+class AnimatableLengthPoint FINAL : public AnimatableValue {
public:
virtual ~AnimatableLengthPoint() { }
- static PassRefPtr<AnimatableLengthPoint> create(PassRefPtr<AnimatableValue> x, PassRefPtr<AnimatableValue> y)
+ static PassRefPtrWillBeRawPtr<AnimatableLengthPoint> create(PassRefPtrWillBeRawPtr<AnimatableValue> x, PassRefPtrWillBeRawPtr<AnimatableValue> y)
{
- return adoptRef(new AnimatableLengthPoint(x, y));
+ return adoptRefWillBeNoop(new AnimatableLengthPoint(x, y));
}
const AnimatableValue* x() const { return m_x.get(); }
const AnimatableValue* y() const { return m_y.get(); }
+ virtual void trace(Visitor*) OVERRIDE;
+
protected:
- virtual PassRefPtr<AnimatableValue> interpolateTo(const AnimatableValue*, double fraction) const OVERRIDE;
- virtual PassRefPtr<AnimatableValue> addWith(const AnimatableValue*) const OVERRIDE;
+ virtual PassRefPtrWillBeRawPtr<AnimatableValue> interpolateTo(const AnimatableValue*, double fraction) const OVERRIDE;
private:
- AnimatableLengthPoint(PassRefPtr<AnimatableValue> x, PassRefPtr<AnimatableValue> y)
+ AnimatableLengthPoint(PassRefPtrWillBeRawPtr<AnimatableValue> x, PassRefPtrWillBeRawPtr<AnimatableValue> y)
: m_x(x)
, m_y(y)
{
@@ -58,8 +59,8 @@ private:
virtual AnimatableType type() const OVERRIDE { return TypeLengthPoint; }
virtual bool equalTo(const AnimatableValue*) const OVERRIDE;
- RefPtr<AnimatableValue> m_x;
- RefPtr<AnimatableValue> m_y;
+ RefPtrWillBeMember<AnimatableValue> m_x;
+ RefPtrWillBeMember<AnimatableValue> m_y;
};
inline const AnimatableLengthPoint* toAnimatableLengthPoint(const AnimatableValue* value)
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimatableLengthPoint3D.cpp b/chromium/third_party/WebKit/Source/core/animation/AnimatableLengthPoint3D.cpp
new file mode 100644
index 00000000000..402f0a8a707
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimatableLengthPoint3D.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2014 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "core/animation/AnimatableLengthPoint3D.h"
+
+namespace WebCore {
+
+PassRefPtrWillBeRawPtr<AnimatableValue> AnimatableLengthPoint3D::interpolateTo(const AnimatableValue* value, double fraction) const
+{
+ const AnimatableLengthPoint3D* lengthPoint = toAnimatableLengthPoint3D(value);
+ return AnimatableLengthPoint3D::create(
+ AnimatableValue::interpolate(this->x(), lengthPoint->x(), fraction),
+ AnimatableValue::interpolate(this->y(), lengthPoint->y(), fraction),
+ AnimatableValue::interpolate(this->z(), lengthPoint->z(), fraction));
+}
+
+bool AnimatableLengthPoint3D::equalTo(const AnimatableValue* value) const
+{
+ const AnimatableLengthPoint3D* lengthPoint = toAnimatableLengthPoint3D(value);
+ return x()->equals(lengthPoint->x()) && y()->equals(lengthPoint->y()) && z()->equals(lengthPoint->z());
+}
+
+void AnimatableLengthPoint3D::trace(Visitor* visitor)
+{
+ visitor->trace(m_x);
+ visitor->trace(m_y);
+ visitor->trace(m_z);
+ AnimatableValue::trace(visitor);
+}
+
+}
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimatableLengthPoint3D.h b/chromium/third_party/WebKit/Source/core/animation/AnimatableLengthPoint3D.h
new file mode 100644
index 00000000000..0e3650ffae5
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimatableLengthPoint3D.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2014 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef AnimatableLengthPoint3D_h
+#define AnimatableLengthPoint3D_h
+
+#include "core/animation/AnimatableValue.h"
+
+namespace WebCore {
+
+class AnimatableLengthPoint3D FINAL : public AnimatableValue {
+public:
+ virtual ~AnimatableLengthPoint3D() { }
+ static PassRefPtrWillBeRawPtr<AnimatableLengthPoint3D> create(PassRefPtrWillBeRawPtr<AnimatableValue> x, PassRefPtrWillBeRawPtr<AnimatableValue> y, PassRefPtrWillBeRawPtr<AnimatableValue> z)
+ {
+ return adoptRefWillBeNoop(new AnimatableLengthPoint3D(x, y, z));
+ }
+ const AnimatableValue* x() const { return m_x.get(); }
+ const AnimatableValue* y() const { return m_y.get(); }
+ const AnimatableValue* z() const { return m_z.get(); }
+
+ virtual void trace(Visitor*) OVERRIDE;
+
+protected:
+ virtual PassRefPtrWillBeRawPtr<AnimatableValue> interpolateTo(const AnimatableValue*, double fraction) const OVERRIDE;
+
+private:
+ AnimatableLengthPoint3D(PassRefPtrWillBeRawPtr<AnimatableValue> x, PassRefPtrWillBeRawPtr<AnimatableValue> y, PassRefPtrWillBeRawPtr<AnimatableValue> z)
+ : m_x(x)
+ , m_y(y)
+ , m_z(z)
+ {
+ }
+ virtual AnimatableType type() const OVERRIDE { return TypeLengthPoint3D; }
+ virtual bool equalTo(const AnimatableValue*) const OVERRIDE;
+
+ RefPtrWillBeMember<AnimatableValue> m_x;
+ RefPtrWillBeMember<AnimatableValue> m_y;
+ RefPtrWillBeMember<AnimatableValue> m_z;
+};
+
+inline const AnimatableLengthPoint3D* toAnimatableLengthPoint3D(const AnimatableValue* value)
+{
+ ASSERT_WITH_SECURITY_IMPLICATION(value && value->isLengthPoint3D());
+ return static_cast<const AnimatableLengthPoint3D*>(value);
+}
+
+} // namespace WebCore
+
+#endif // AnimatableLengthPoint3D_h
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimatableLengthSize.cpp b/chromium/third_party/WebKit/Source/core/animation/AnimatableLengthSize.cpp
index b422f39a931..c63239536c0 100644
--- a/chromium/third_party/WebKit/Source/core/animation/AnimatableLengthSize.cpp
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimatableLengthSize.cpp
@@ -33,7 +33,7 @@
namespace WebCore {
-PassRefPtr<AnimatableValue> AnimatableLengthSize::interpolateTo(const AnimatableValue* value, double fraction) const
+PassRefPtrWillBeRawPtr<AnimatableValue> AnimatableLengthSize::interpolateTo(const AnimatableValue* value, double fraction) const
{
const AnimatableLengthSize* lengthSize = toAnimatableLengthSize(value);
return AnimatableLengthSize::create(
@@ -41,18 +41,17 @@ PassRefPtr<AnimatableValue> AnimatableLengthSize::interpolateTo(const Animatable
AnimatableValue::interpolate(this->height(), lengthSize->height(), fraction));
}
-PassRefPtr<AnimatableValue> AnimatableLengthSize::addWith(const AnimatableValue* value) const
+bool AnimatableLengthSize::equalTo(const AnimatableValue* value) const
{
const AnimatableLengthSize* lengthSize = toAnimatableLengthSize(value);
- return AnimatableLengthSize::create(
- AnimatableValue::add(this->width(), lengthSize->width()),
- AnimatableValue::add(this->height(), lengthSize->height()));
+ return width()->equals(lengthSize->width()) && height()->equals(lengthSize->height());
}
-bool AnimatableLengthSize::equalTo(const AnimatableValue* value) const
+void AnimatableLengthSize::trace(Visitor* visitor)
{
- const AnimatableLengthSize* lengthSize = toAnimatableLengthSize(value);
- return width()->equals(lengthSize->width()) && height()->equals(lengthSize->height());
+ visitor->trace(m_width);
+ visitor->trace(m_height);
+ AnimatableValue::trace(visitor);
}
}
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimatableLengthSize.h b/chromium/third_party/WebKit/Source/core/animation/AnimatableLengthSize.h
index 55dcc4090d3..a572468e18e 100644
--- a/chromium/third_party/WebKit/Source/core/animation/AnimatableLengthSize.h
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimatableLengthSize.h
@@ -35,22 +35,23 @@
namespace WebCore {
-class AnimatableLengthSize : public AnimatableValue {
+class AnimatableLengthSize FINAL : public AnimatableValue {
public:
virtual ~AnimatableLengthSize() { }
- static PassRefPtr<AnimatableLengthSize> create(PassRefPtr<AnimatableValue> width, PassRefPtr<AnimatableValue> height)
+ static PassRefPtrWillBeRawPtr<AnimatableLengthSize> create(PassRefPtrWillBeRawPtr<AnimatableValue> width, PassRefPtrWillBeRawPtr<AnimatableValue> height)
{
- return adoptRef(new AnimatableLengthSize(width, height));
+ return adoptRefWillBeNoop(new AnimatableLengthSize(width, height));
}
const AnimatableValue* width() const { return m_width.get(); }
const AnimatableValue* height() const { return m_height.get(); }
+ virtual void trace(Visitor*) OVERRIDE;
+
protected:
- virtual PassRefPtr<AnimatableValue> interpolateTo(const AnimatableValue*, double fraction) const OVERRIDE;
- virtual PassRefPtr<AnimatableValue> addWith(const AnimatableValue*) const OVERRIDE;
+ virtual PassRefPtrWillBeRawPtr<AnimatableValue> interpolateTo(const AnimatableValue*, double fraction) const OVERRIDE;
private:
- AnimatableLengthSize(PassRefPtr<AnimatableValue> width, PassRefPtr<AnimatableValue> height)
+ AnimatableLengthSize(PassRefPtrWillBeRawPtr<AnimatableValue> width, PassRefPtrWillBeRawPtr<AnimatableValue> height)
: m_width(width)
, m_height(height)
{
@@ -58,8 +59,8 @@ private:
virtual AnimatableType type() const OVERRIDE { return TypeLengthSize; }
virtual bool equalTo(const AnimatableValue*) const OVERRIDE;
- RefPtr<AnimatableValue> m_width;
- RefPtr<AnimatableValue> m_height;
+ RefPtrWillBeMember<AnimatableValue> m_width;
+ RefPtrWillBeMember<AnimatableValue> m_height;
};
DEFINE_ANIMATABLE_VALUE_TYPE_CASTS(AnimatableLengthSize, isLengthSize());
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimatableLengthTest.cpp b/chromium/third_party/WebKit/Source/core/animation/AnimatableLengthTest.cpp
index 3574a66279b..c5887e239c8 100644
--- a/chromium/third_party/WebKit/Source/core/animation/AnimatableLengthTest.cpp
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimatableLengthTest.cpp
@@ -1,367 +1,73 @@
-/*
- * Copyright (c) 2013, Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
#include "config.h"
#include "core/animation/AnimatableLength.h"
-
-#include "core/animation/AnimatableValueTestHelper.h"
-#include "core/css/CSSCalculationValue.h"
-#include "core/css/CSSPrimitiveValue.h"
-#include "core/css/CSSToLengthConversionData.h"
-#include "core/rendering/style/RenderStyle.h"
-#include "core/rendering/style/StyleInheritedData.h"
#include "platform/CalculationValue.h"
-#include "wtf/MathExtras.h"
#include <gtest/gtest.h>
-#define EXPECT_ROUNDTRIP(a, f) EXPECT_REFV_EQ(a, f(a.get()))
-
namespace WebCore {
-class AnimationAnimatableLengthTest : public ::testing::Test {
-protected:
- AnimationAnimatableLengthTest()
- : style(RenderStyle::createDefaultStyle())
- , conversionDataZoom1(style.get(), style.get(), 1.0f)
- , conversionDataZoom3(style.get(), style.get(), 3.0f)
- {
- }
-
- PassRefPtr<AnimatableLength> create(double value, CSSPrimitiveValue::UnitTypes type)
- {
- return AnimatableLength::create(CSSPrimitiveValue::create(value, type).get());
- }
-
- PassRefPtr<AnimatableLength> create(double valueLeft, CSSPrimitiveValue::UnitTypes typeLeft, double valueRight, CSSPrimitiveValue::UnitTypes typeRight)
- {
- return AnimatableLength::create(createCalc(valueLeft, typeLeft, valueRight, typeRight).get());
- }
-
- PassRefPtr<CSSCalcValue> createCalc(double valueLeft, CSSPrimitiveValue::UnitTypes typeLeft, double valueRight, CSSPrimitiveValue::UnitTypes typeRight)
- {
- return CSSCalcValue::create(CSSCalcValue::createExpressionNode(
- CSSCalcValue::createExpressionNode(CSSPrimitiveValue::create(valueLeft, typeLeft), valueLeft == trunc(valueLeft)),
- CSSCalcValue::createExpressionNode(CSSPrimitiveValue::create(valueRight, typeRight), valueRight == trunc(valueRight)),
- CalcAdd
- ));
- }
-
- PassRefPtr<CSSValue> toCSSValue(CSSValue* cssValue)
- {
- return AnimatableLength::create(cssValue)->toCSSValue();
- }
-
- AnimatableLength::NumberUnitType commonUnitType(PassRefPtr<AnimatableLength> a, PassRefPtr<AnimatableLength> b)
- {
- return a->commonUnitType(b.get());
- }
+namespace {
- bool isUnitlessZero(PassRefPtr<AnimatableLength> a)
+ PassRefPtrWillBeRawPtr<AnimatableLength> create(const Length& length, double zoom = 1)
{
- return a->isUnitlessZero();
+ return AnimatableLength::create(length, zoom);
}
- RefPtr<RenderStyle> style;
- CSSToLengthConversionData conversionDataZoom1;
- CSSToLengthConversionData conversionDataZoom3;
-};
-
-TEST_F(AnimationAnimatableLengthTest, CanCreateFrom)
-{
- EXPECT_TRUE(AnimatableLength::canCreateFrom(CSSPrimitiveValue::create(5, CSSPrimitiveValue::CSS_PX).get()));
- EXPECT_TRUE(AnimatableLength::canCreateFrom(CSSPrimitiveValue::create(5, CSSPrimitiveValue::CSS_CM).get()));
- EXPECT_TRUE(AnimatableLength::canCreateFrom(CSSPrimitiveValue::create(5, CSSPrimitiveValue::CSS_MM).get()));
- EXPECT_TRUE(AnimatableLength::canCreateFrom(CSSPrimitiveValue::create(5, CSSPrimitiveValue::CSS_IN).get()));
- EXPECT_TRUE(AnimatableLength::canCreateFrom(CSSPrimitiveValue::create(5, CSSPrimitiveValue::CSS_PT).get()));
- EXPECT_TRUE(AnimatableLength::canCreateFrom(CSSPrimitiveValue::create(5, CSSPrimitiveValue::CSS_PC).get()));
- EXPECT_TRUE(AnimatableLength::canCreateFrom(CSSPrimitiveValue::create(5, CSSPrimitiveValue::CSS_EMS).get()));
- EXPECT_TRUE(AnimatableLength::canCreateFrom(CSSPrimitiveValue::create(5, CSSPrimitiveValue::CSS_EXS).get()));
- EXPECT_TRUE(AnimatableLength::canCreateFrom(CSSPrimitiveValue::create(5, CSSPrimitiveValue::CSS_REMS).get()));
- EXPECT_TRUE(AnimatableLength::canCreateFrom(CSSPrimitiveValue::create(5, CSSPrimitiveValue::CSS_PERCENTAGE).get()));
- EXPECT_TRUE(AnimatableLength::canCreateFrom(CSSPrimitiveValue::create(5, CSSPrimitiveValue::CSS_VW).get()));
- EXPECT_TRUE(AnimatableLength::canCreateFrom(CSSPrimitiveValue::create(5, CSSPrimitiveValue::CSS_VH).get()));
- EXPECT_TRUE(AnimatableLength::canCreateFrom(CSSPrimitiveValue::create(5, CSSPrimitiveValue::CSS_VMIN).get()));
- EXPECT_TRUE(AnimatableLength::canCreateFrom(CSSPrimitiveValue::create(5, CSSPrimitiveValue::CSS_VMAX).get()));
-
- EXPECT_TRUE(AnimatableLength::canCreateFrom(createCalc(3, CSSPrimitiveValue::CSS_PX, 5, CSSPrimitiveValue::CSS_CM).get()));
- EXPECT_TRUE(AnimatableLength::canCreateFrom(CSSPrimitiveValue::create(createCalc(3, CSSPrimitiveValue::CSS_PX, 5, CSSPrimitiveValue::CSS_CM)).get()));
-
- EXPECT_FALSE(AnimatableLength::canCreateFrom(CSSPrimitiveValue::create("NaN", CSSPrimitiveValue::CSS_STRING).get()));
-}
-
-TEST_F(AnimationAnimatableLengthTest, Create)
-{
- EXPECT_TRUE(static_cast<bool>(create(5, CSSPrimitiveValue::CSS_PX).get()));
- EXPECT_TRUE(static_cast<bool>(create(5, CSSPrimitiveValue::CSS_CM).get()));
- EXPECT_TRUE(static_cast<bool>(create(5, CSSPrimitiveValue::CSS_MM).get()));
- EXPECT_TRUE(static_cast<bool>(create(5, CSSPrimitiveValue::CSS_IN).get()));
- EXPECT_TRUE(static_cast<bool>(create(5, CSSPrimitiveValue::CSS_PT).get()));
- EXPECT_TRUE(static_cast<bool>(create(5, CSSPrimitiveValue::CSS_PC).get()));
- EXPECT_TRUE(static_cast<bool>(create(5, CSSPrimitiveValue::CSS_EMS).get()));
- EXPECT_TRUE(static_cast<bool>(create(5, CSSPrimitiveValue::CSS_EXS).get()));
- EXPECT_TRUE(static_cast<bool>(create(5, CSSPrimitiveValue::CSS_REMS).get()));
- EXPECT_TRUE(static_cast<bool>(create(5, CSSPrimitiveValue::CSS_PERCENTAGE).get()));
- EXPECT_TRUE(static_cast<bool>(create(5, CSSPrimitiveValue::CSS_VW).get()));
- EXPECT_TRUE(static_cast<bool>(create(5, CSSPrimitiveValue::CSS_VH).get()));
- EXPECT_TRUE(static_cast<bool>(create(5, CSSPrimitiveValue::CSS_VMIN).get()));
- EXPECT_TRUE(static_cast<bool>(create(5, CSSPrimitiveValue::CSS_VMAX).get()));
-
- EXPECT_TRUE(static_cast<bool>(
- AnimatableLength::create(createCalc(3, CSSPrimitiveValue::CSS_PX, 5, CSSPrimitiveValue::CSS_CM).get()).get()
- ));
- EXPECT_TRUE(static_cast<bool>(
- AnimatableLength::create(CSSPrimitiveValue::create(createCalc(3, CSSPrimitiveValue::CSS_PX, 5, CSSPrimitiveValue::CSS_CM)).get()).get()
- ));
-}
-
-
-TEST_F(AnimationAnimatableLengthTest, ToCSSValue)
-{
-
- EXPECT_ROUNDTRIP(CSSPrimitiveValue::create(-5, CSSPrimitiveValue::CSS_PX), toCSSValue);
- EXPECT_ROUNDTRIP(CSSPrimitiveValue::create(-5, CSSPrimitiveValue::CSS_CM), toCSSValue);
- EXPECT_ROUNDTRIP(CSSPrimitiveValue::create(-5, CSSPrimitiveValue::CSS_MM), toCSSValue);
- EXPECT_ROUNDTRIP(CSSPrimitiveValue::create(-5, CSSPrimitiveValue::CSS_IN), toCSSValue);
- EXPECT_ROUNDTRIP(CSSPrimitiveValue::create(-5, CSSPrimitiveValue::CSS_PT), toCSSValue);
- EXPECT_ROUNDTRIP(CSSPrimitiveValue::create(-5, CSSPrimitiveValue::CSS_PC), toCSSValue);
- EXPECT_ROUNDTRIP(CSSPrimitiveValue::create(-5, CSSPrimitiveValue::CSS_EMS), toCSSValue);
- EXPECT_ROUNDTRIP(CSSPrimitiveValue::create(-5, CSSPrimitiveValue::CSS_EXS), toCSSValue);
- EXPECT_ROUNDTRIP(CSSPrimitiveValue::create(-5, CSSPrimitiveValue::CSS_REMS), toCSSValue);
- EXPECT_ROUNDTRIP(CSSPrimitiveValue::create(-5, CSSPrimitiveValue::CSS_PERCENTAGE), toCSSValue);
- EXPECT_ROUNDTRIP(CSSPrimitiveValue::create(-5, CSSPrimitiveValue::CSS_VW), toCSSValue);
- EXPECT_ROUNDTRIP(CSSPrimitiveValue::create(-5, CSSPrimitiveValue::CSS_VH), toCSSValue);
- EXPECT_ROUNDTRIP(CSSPrimitiveValue::create(-5, CSSPrimitiveValue::CSS_VMIN), toCSSValue);
- EXPECT_ROUNDTRIP(CSSPrimitiveValue::create(-5, CSSPrimitiveValue::CSS_VMAX), toCSSValue);
-
- EXPECT_ROUNDTRIP(CSSPrimitiveValue::create(createCalc(3, CSSPrimitiveValue::CSS_PX, 5, CSSPrimitiveValue::CSS_IN)), toCSSValue);
- EXPECT_ROUNDTRIP(CSSPrimitiveValue::create(createCalc(3, CSSPrimitiveValue::CSS_PX, 5, CSSPrimitiveValue::CSS_IN)), toCSSValue);
-}
-
+} // namespace
-TEST_F(AnimationAnimatableLengthTest, ToLength)
+TEST(AnimationAnimatableLengthTest, RoundTripConversion)
{
- EXPECT_EQ(Length(-5, WebCore::Fixed), create(-5, CSSPrimitiveValue::CSS_PX)->toLength(conversionDataZoom1));
- EXPECT_EQ(Length(-15, WebCore::Fixed), create(-5, CSSPrimitiveValue::CSS_PX)->toLength(conversionDataZoom3));
- EXPECT_EQ(Length(0, WebCore::Fixed), create(-5, CSSPrimitiveValue::CSS_PX)->toLength(conversionDataZoom1, NonNegativeValues));
- EXPECT_EQ(Length(0, WebCore::Fixed), create(-5, CSSPrimitiveValue::CSS_PX)->toLength(conversionDataZoom3, NonNegativeValues));
-
- EXPECT_EQ(Length(-5, Percent), create(-5, CSSPrimitiveValue::CSS_PERCENTAGE)->toLength(conversionDataZoom1));
- EXPECT_EQ(Length(-5, Percent), create(-5, CSSPrimitiveValue::CSS_PERCENTAGE)->toLength(conversionDataZoom3));
- EXPECT_EQ(Length(0, Percent), create(-5, CSSPrimitiveValue::CSS_PERCENTAGE)->toLength(conversionDataZoom1, NonNegativeValues));
- EXPECT_EQ(Length(0, Percent), create(-5, CSSPrimitiveValue::CSS_PERCENTAGE)->toLength(conversionDataZoom3, NonNegativeValues));
-
- EXPECT_EQ(
- Length(CalculationValue::create(
- adoptPtr(new CalcExpressionBinaryOperation(
- adoptPtr(new CalcExpressionLength(Length(-5, WebCore::Fixed))),
- adoptPtr(new CalcExpressionLength(Length(-5, Percent))),
- CalcAdd)),
- ValueRangeAll)),
- create(-5, CSSPrimitiveValue::CSS_PX, -5, CSSPrimitiveValue::CSS_PERCENTAGE)->toLength(conversionDataZoom1));
- EXPECT_EQ(
- Length(CalculationValue::create(
- adoptPtr(new CalcExpressionBinaryOperation(
- adoptPtr(new CalcExpressionLength(Length(-15, WebCore::Fixed))),
- adoptPtr(new CalcExpressionLength(Length(-5, Percent))),
- CalcAdd)),
- ValueRangeAll)),
- create(-5, CSSPrimitiveValue::CSS_PX, -5, CSSPrimitiveValue::CSS_PERCENTAGE)->toLength(conversionDataZoom3));
- EXPECT_EQ(
- Length(CalculationValue::create(
- adoptPtr(new CalcExpressionBinaryOperation(
- adoptPtr(new CalcExpressionLength(Length(-5, WebCore::Fixed))),
- adoptPtr(new CalcExpressionLength(Length(-5, Percent))),
- CalcAdd)),
- ValueRangeNonNegative)),
- create(-5, CSSPrimitiveValue::CSS_PX, -5, CSSPrimitiveValue::CSS_PERCENTAGE)->toLength(conversionDataZoom1, NonNegativeValues));
- EXPECT_EQ(
- Length(CalculationValue::create(
- adoptPtr(new CalcExpressionBinaryOperation(
- adoptPtr(new CalcExpressionLength(Length(-15, WebCore::Fixed))),
- adoptPtr(new CalcExpressionLength(Length(-5, Percent))),
- CalcAdd)),
- ValueRangeNonNegative)),
- create(-5, CSSPrimitiveValue::CSS_PX, -5, CSSPrimitiveValue::CSS_PERCENTAGE)->toLength(conversionDataZoom3, NonNegativeValues));
+ EXPECT_EQ(Length(0, Fixed), create(Length(0, Fixed))->length(1, ValueRangeAll));
+ EXPECT_EQ(Length(0, Percent), create(Length(0, Percent))->length(1, ValueRangeAll));
+ EXPECT_EQ(Length(10, Fixed), create(Length(10, Fixed))->length(1, ValueRangeAll));
+ EXPECT_EQ(Length(10, Percent), create(Length(10, Percent))->length(1, ValueRangeAll));
+ EXPECT_EQ(Length(-10, Fixed), create(Length(-10, Fixed))->length(1, ValueRangeAll));
+ EXPECT_EQ(Length(-10, Percent), create(Length(-10, Percent))->length(1, ValueRangeAll));
+ Length calc = Length(CalculationValue::create(PixelsAndPercent(5, 10), ValueRangeAll));
+ EXPECT_EQ(calc, create(calc)->length(1, ValueRangeAll));
}
-TEST_F(AnimationAnimatableLengthTest, Interpolate)
+TEST(AnimationAnimatableLengthTest, ValueRangeNonNegative)
{
- RefPtr<AnimatableLength> from10px = create(10, CSSPrimitiveValue::CSS_PX);
- RefPtr<AnimatableLength> to20pxAsInches = create(20.0 / 96, CSSPrimitiveValue::CSS_IN);
-
- EXPECT_REFV_EQ(create(5, CSSPrimitiveValue::CSS_PX),
- AnimatableValue::interpolate(from10px.get(), to20pxAsInches.get(), -0.5));
-
- EXPECT_REFV_EQ(create(10, CSSPrimitiveValue::CSS_PX),
- AnimatableValue::interpolate(from10px.get(), to20pxAsInches.get(), 0));
- EXPECT_REFV_EQ(create(14, CSSPrimitiveValue::CSS_PX),
- AnimatableValue::interpolate(from10px.get(), to20pxAsInches.get(), 0.4));
- EXPECT_REFV_EQ(create(15, CSSPrimitiveValue::CSS_PX),
- AnimatableValue::interpolate(from10px.get(), to20pxAsInches.get(), 0.5));
- EXPECT_REFV_EQ(create(16, CSSPrimitiveValue::CSS_PX),
- AnimatableValue::interpolate(from10px.get(), to20pxAsInches.get(), 0.6));
- EXPECT_REFV_EQ(create(20.0 / 96, CSSPrimitiveValue::CSS_IN),
- AnimatableValue::interpolate(from10px.get(), to20pxAsInches.get(), 1));
- EXPECT_REFV_EQ(create(25, CSSPrimitiveValue::CSS_PX),
- AnimatableValue::interpolate(from10px.get(), to20pxAsInches.get(), 1.5));
-
- RefPtr<AnimatableLength> from10em = create(10, CSSPrimitiveValue::CSS_EMS);
- RefPtr<AnimatableLength> to20rem = create(20, CSSPrimitiveValue::CSS_REMS);
- EXPECT_REFV_EQ(create(15, CSSPrimitiveValue::CSS_EMS, -10, CSSPrimitiveValue::CSS_REMS),
- AnimatableValue::interpolate(from10em.get(), to20rem.get(), -0.5));
- EXPECT_REFV_EQ(create(10, CSSPrimitiveValue::CSS_EMS),
- AnimatableValue::interpolate(from10em.get(), to20rem.get(), 0));
- EXPECT_REFV_EQ(create(6, CSSPrimitiveValue::CSS_EMS, 8, CSSPrimitiveValue::CSS_REMS),
- AnimatableValue::interpolate(from10em.get(), to20rem.get(), 0.4));
- EXPECT_REFV_EQ(create(5, CSSPrimitiveValue::CSS_EMS, 10, CSSPrimitiveValue::CSS_REMS),
- AnimatableValue::interpolate(from10em.get(), to20rem.get(), 0.5));
- EXPECT_REFV_EQ(create(4, CSSPrimitiveValue::CSS_EMS, 12, CSSPrimitiveValue::CSS_REMS),
- AnimatableValue::interpolate(from10em.get(), to20rem.get(), 0.6));
- EXPECT_REFV_EQ(create(20, CSSPrimitiveValue::CSS_REMS),
- AnimatableValue::interpolate(from10em.get(), to20rem.get(), 1));
- EXPECT_REFV_EQ(create(-5, CSSPrimitiveValue::CSS_EMS, 30, CSSPrimitiveValue::CSS_REMS),
- AnimatableValue::interpolate(from10em.get(), to20rem.get(), 1.5));
-
- // Zero values are typeless and hence we can don't get a calc
- RefPtr<AnimatableLength> from0px = create(0, CSSPrimitiveValue::CSS_PX);
- EXPECT_REFV_EQ(create(-10, CSSPrimitiveValue::CSS_REMS),
- AnimatableValue::interpolate(from0px.get(), to20rem.get(), -0.5));
- // At t=0, interpolate always returns the "from" value.
- EXPECT_REFV_EQ(create(0, CSSPrimitiveValue::CSS_PX),
- AnimatableValue::interpolate(from0px.get(), to20rem.get(), 0));
- EXPECT_REFV_EQ(create(10, CSSPrimitiveValue::CSS_REMS),
- AnimatableValue::interpolate(from0px.get(), to20rem.get(), 0.5));
- EXPECT_REFV_EQ(create(20, CSSPrimitiveValue::CSS_REMS),
- AnimatableValue::interpolate(from0px.get(), to20rem.get(), 1.0));
- EXPECT_REFV_EQ(create(30, CSSPrimitiveValue::CSS_REMS),
- AnimatableValue::interpolate(from0px.get(), to20rem.get(), 1.5));
-
- // Except 0% which is special
- RefPtr<AnimatableLength> from0percent = create(0, CSSPrimitiveValue::CSS_PERCENTAGE);
- EXPECT_REFV_EQ(create(0, CSSPrimitiveValue::CSS_PERCENTAGE, -10, CSSPrimitiveValue::CSS_REMS),
- AnimatableValue::interpolate(from0percent.get(), to20rem.get(), -0.5));
- // At t=0, interpolate always returns the "from" value.
- EXPECT_REFV_EQ(create(0, CSSPrimitiveValue::CSS_PERCENTAGE),
- AnimatableValue::interpolate(from0percent.get(), to20rem.get(), 0));
- EXPECT_REFV_EQ(create(0, CSSPrimitiveValue::CSS_PERCENTAGE, 10, CSSPrimitiveValue::CSS_REMS),
- AnimatableValue::interpolate(from0percent.get(), to20rem.get(), 0.5));
- // At t=1, interpolate always returns the "to" value.
- EXPECT_REFV_EQ(create(20, CSSPrimitiveValue::CSS_REMS),
- AnimatableValue::interpolate(from0percent.get(), to20rem.get(), 1.0));
- EXPECT_REFV_EQ(create(0, CSSPrimitiveValue::CSS_PERCENTAGE, 30, CSSPrimitiveValue::CSS_REMS),
- AnimatableValue::interpolate(from0percent.get(), to20rem.get(), 1.5));
+ EXPECT_EQ(Length(10, Fixed), create(Length(10, Fixed))->length(1, ValueRangeNonNegative));
+ EXPECT_EQ(Length(10, Percent), create(Length(10, Percent))->length(1, ValueRangeNonNegative));
+ EXPECT_EQ(Length(0, Fixed), create(Length(-10, Fixed))->length(1, ValueRangeNonNegative));
+ EXPECT_EQ(Length(0, Percent), create(Length(-10, Percent))->length(1, ValueRangeNonNegative));
+ Length calc = Length(CalculationValue::create(PixelsAndPercent(-5, -10), ValueRangeNonNegative));
+ EXPECT_TRUE(calc == create(calc)->length(1, ValueRangeNonNegative));
}
-TEST_F(AnimationAnimatableLengthTest, Add)
+TEST(AnimationAnimatableLengthTest, Zoom)
{
- EXPECT_REFV_EQ(create(10, CSSPrimitiveValue::CSS_PX),
- AnimatableValue::add(create(10, CSSPrimitiveValue::CSS_PX).get(), create(0, CSSPrimitiveValue::CSS_MM).get()));
- EXPECT_REFV_EQ(create(100, CSSPrimitiveValue::CSS_PX),
- AnimatableValue::add(create(4, CSSPrimitiveValue::CSS_PX).get(), create(1, CSSPrimitiveValue::CSS_IN).get()));
- EXPECT_REFV_EQ(
- create(10, CSSPrimitiveValue::CSS_EMS, 20, CSSPrimitiveValue::CSS_REMS),
- AnimatableValue::add(create(10, CSSPrimitiveValue::CSS_EMS).get(), create(20, CSSPrimitiveValue::CSS_REMS).get()));
- EXPECT_REFV_EQ(
- create(10, CSSPrimitiveValue::CSS_EMS),
- AnimatableValue::add(create(10, CSSPrimitiveValue::CSS_EMS).get(), create(0, CSSPrimitiveValue::CSS_REMS).get()));
- EXPECT_REFV_EQ(
- create(20, CSSPrimitiveValue::CSS_REMS),
- AnimatableValue::add(create(0, CSSPrimitiveValue::CSS_EMS).get(), create(20, CSSPrimitiveValue::CSS_REMS).get()));
-
- // Check you actually get the reference back for zero optimization
- RefPtr<AnimatableLength> rems20 = create(20, CSSPrimitiveValue::CSS_REMS);
- EXPECT_EQ(rems20.get(), AnimatableValue::add(create(0, CSSPrimitiveValue::CSS_EMS).get(), rems20.get()).get());
- EXPECT_EQ(rems20.get(), AnimatableValue::add(rems20.get(), create(0, CSSPrimitiveValue::CSS_EMS).get()).get());
-
- // Except 0% which is special
- RefPtr<AnimatableLength> zeropercent = create(0, CSSPrimitiveValue::CSS_PERCENTAGE);
- EXPECT_REFV_EQ(create(0, CSSPrimitiveValue::CSS_PERCENTAGE, -10, CSSPrimitiveValue::CSS_REMS),
- AnimatableValue::add(zeropercent.get(), create(-10, CSSPrimitiveValue::CSS_REMS).get()));
- EXPECT_REFV_EQ(create(-10, CSSPrimitiveValue::CSS_REMS, 0, CSSPrimitiveValue::CSS_PERCENTAGE),
- AnimatableValue::add(create(-10, CSSPrimitiveValue::CSS_REMS).get(), zeropercent.get()));
+ EXPECT_EQ(Length(4, Fixed), create(Length(10, Fixed), 5)->length(2, ValueRangeAll));
+ EXPECT_EQ(Length(10, Percent), create(Length(10, Percent), 5)->length(2, ValueRangeAll));
+ Length calc = Length(CalculationValue::create(PixelsAndPercent(5, 10), ValueRangeAll));
+ Length result = Length(CalculationValue::create(PixelsAndPercent(2, 10), ValueRangeAll));
+ EXPECT_TRUE(result == create(calc, 5)->length(2, ValueRangeAll));
}
-TEST_F(AnimationAnimatableLengthTest, IsUnitless)
+TEST(AnimationAnimatableLengthTest, Equals)
{
- EXPECT_TRUE(isUnitlessZero(create(0, CSSPrimitiveValue::CSS_PX)));
- EXPECT_FALSE(isUnitlessZero(create(0, CSSPrimitiveValue::CSS_PERCENTAGE)));
- EXPECT_TRUE(isUnitlessZero(create(0, CSSPrimitiveValue::CSS_EMS)));
- EXPECT_TRUE(isUnitlessZero(create(0, CSSPrimitiveValue::CSS_EXS)));
- EXPECT_TRUE(isUnitlessZero(create(0, CSSPrimitiveValue::CSS_REMS)));
- EXPECT_TRUE(isUnitlessZero(create(0, CSSPrimitiveValue::CSS_VW)));
- EXPECT_TRUE(isUnitlessZero(create(0, CSSPrimitiveValue::CSS_VH)));
- EXPECT_TRUE(isUnitlessZero(create(0, CSSPrimitiveValue::CSS_VMIN)));
- EXPECT_TRUE(isUnitlessZero(create(0, CSSPrimitiveValue::CSS_VMAX)));
-
- EXPECT_FALSE(isUnitlessZero(create(1, CSSPrimitiveValue::CSS_PX)));
- EXPECT_FALSE(isUnitlessZero(create(2, CSSPrimitiveValue::CSS_PERCENTAGE)));
- EXPECT_FALSE(isUnitlessZero(create(3, CSSPrimitiveValue::CSS_EMS)));
- EXPECT_FALSE(isUnitlessZero(create(4, CSSPrimitiveValue::CSS_EXS)));
- EXPECT_FALSE(isUnitlessZero(create(5, CSSPrimitiveValue::CSS_REMS)));
- EXPECT_FALSE(isUnitlessZero(create(6, CSSPrimitiveValue::CSS_VW)));
- EXPECT_FALSE(isUnitlessZero(create(7, CSSPrimitiveValue::CSS_VH)));
- EXPECT_FALSE(isUnitlessZero(create(8, CSSPrimitiveValue::CSS_VMIN)));
- EXPECT_FALSE(isUnitlessZero(create(9, CSSPrimitiveValue::CSS_VMAX)));
+ EXPECT_TRUE(create(Length(10, Fixed))->equals(create(Length(10, Fixed)).get()));
+ EXPECT_TRUE(create(Length(20, Percent))->equals(create(Length(20, Percent)).get()));
+ EXPECT_FALSE(create(Length(10, Fixed))->equals(create(Length(10, Percent)).get()));
+ EXPECT_FALSE(create(Length(0, Percent))->equals(create(Length(0, Fixed)).get()));
+ Length calc = Length(CalculationValue::create(PixelsAndPercent(5, 10), ValueRangeAll));
+ EXPECT_TRUE(create(calc)->equals(create(calc).get()));
+ EXPECT_FALSE(create(calc)->equals(create(Length(10, Percent)).get()));
}
-TEST_F(AnimationAnimatableLengthTest, CommonUnitType)
+TEST(AnimationAnimatableLengthTest, Interpolate)
{
- RefPtr<AnimatableLength> length10px = create(10, CSSPrimitiveValue::CSS_PX);
- EXPECT_EQ(AnimatableLength::UnitTypePixels, commonUnitType(length10px, create(1, CSSPrimitiveValue::CSS_PX).get()));
- EXPECT_EQ(AnimatableLength::UnitTypeCalc, commonUnitType(length10px, create(2, CSSPrimitiveValue::CSS_PERCENTAGE).get()));
- EXPECT_EQ(AnimatableLength::UnitTypeCalc, commonUnitType(length10px, create(3, CSSPrimitiveValue::CSS_EMS).get()));
- EXPECT_EQ(AnimatableLength::UnitTypeCalc, commonUnitType(length10px, create(4, CSSPrimitiveValue::CSS_PX, 5, CSSPrimitiveValue::CSS_CM).get()));
- EXPECT_EQ(AnimatableLength::UnitTypeCalc, commonUnitType(length10px, create(0, CSSPrimitiveValue::CSS_PERCENTAGE).get()));
-
- RefPtr<AnimatableLength> length0px = create(0, CSSPrimitiveValue::CSS_PX);
- EXPECT_EQ(AnimatableLength::UnitTypePixels, commonUnitType(length0px, create(1, CSSPrimitiveValue::CSS_PX).get()));
- EXPECT_EQ(AnimatableLength::UnitTypePercentage, commonUnitType(length0px, create(2, CSSPrimitiveValue::CSS_PERCENTAGE).get()));
- EXPECT_EQ(AnimatableLength::UnitTypeFontSize, commonUnitType(length0px, create(3, CSSPrimitiveValue::CSS_EMS).get()));
- EXPECT_EQ(AnimatableLength::UnitTypeCalc, commonUnitType(length0px, create(4, CSSPrimitiveValue::CSS_PX, 5, CSSPrimitiveValue::CSS_CM).get()));
- EXPECT_EQ(AnimatableLength::UnitTypePercentage, commonUnitType(length0px, create(0, CSSPrimitiveValue::CSS_PERCENTAGE).get()));
-
- RefPtr<AnimatableLength> length0percent = create(0, CSSPrimitiveValue::CSS_PERCENTAGE);
- EXPECT_EQ(AnimatableLength::UnitTypeCalc, commonUnitType(length0percent, create(1, CSSPrimitiveValue::CSS_PX).get()));
- EXPECT_EQ(AnimatableLength::UnitTypePercentage, commonUnitType(length0percent, create(2, CSSPrimitiveValue::CSS_PERCENTAGE).get()));
- EXPECT_EQ(AnimatableLength::UnitTypeCalc, commonUnitType(length0percent, create(3, CSSPrimitiveValue::CSS_EMS).get()));
- EXPECT_EQ(AnimatableLength::UnitTypeCalc, commonUnitType(length0percent, create(4, CSSPrimitiveValue::CSS_PX, 5, CSSPrimitiveValue::CSS_CM).get()));
- EXPECT_EQ(AnimatableLength::UnitTypePercentage, commonUnitType(length0percent, create(0, CSSPrimitiveValue::CSS_PERCENTAGE).get()));
-
- RefPtr<AnimatableLength> lengthCalc = create(3, CSSPrimitiveValue::CSS_PX, 5, CSSPrimitiveValue::CSS_CM);
- EXPECT_EQ(AnimatableLength::UnitTypeCalc, commonUnitType(lengthCalc, create(1, CSSPrimitiveValue::CSS_PX).get()));
- EXPECT_EQ(AnimatableLength::UnitTypeCalc, commonUnitType(lengthCalc, create(2, CSSPrimitiveValue::CSS_PERCENTAGE).get()));
- EXPECT_EQ(AnimatableLength::UnitTypeCalc, commonUnitType(lengthCalc, create(3, CSSPrimitiveValue::CSS_EMS).get()));
- EXPECT_EQ(AnimatableLength::UnitTypeCalc, commonUnitType(lengthCalc, create(4, CSSPrimitiveValue::CSS_PX, 5, CSSPrimitiveValue::CSS_CM).get()));
- EXPECT_EQ(AnimatableLength::UnitTypeCalc, commonUnitType(lengthCalc, create(0, CSSPrimitiveValue::CSS_PERCENTAGE).get()));
+ EXPECT_TRUE(AnimatableValue::interpolate(create(Length(10, Fixed)).get(), create(Length(0, Fixed)).get(), 0.2)->equals(create(Length(8, Fixed)).get()));
+ EXPECT_TRUE(AnimatableValue::interpolate(create(Length(4, Percent)).get(), create(Length(12, Percent)).get(), 0.25)->equals(create(Length(6, Percent)).get()));
+ Length calc = Length(CalculationValue::create(PixelsAndPercent(12, 4), ValueRangeAll));
+ EXPECT_TRUE(AnimatableValue::interpolate(create(Length(20, Fixed)).get(), create(Length(10, Percent)).get(), 0.4)->equals(create(calc).get()));
}
} // namespace WebCore
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimatableNeutral.h b/chromium/third_party/WebKit/Source/core/animation/AnimatableNeutral.h
index 5b8759ce45b..16f8595b29f 100644
--- a/chromium/third_party/WebKit/Source/core/animation/AnimatableNeutral.h
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimatableNeutral.h
@@ -35,16 +35,18 @@
namespace WebCore {
-class AnimatableNeutral : public AnimatableValue {
+class AnimatableNeutral FINAL : public AnimatableValue {
public:
virtual ~AnimatableNeutral() { }
+ virtual void trace(Visitor* visitor) OVERRIDE { AnimatableValue::trace(visitor); }
+
protected:
- static PassRefPtr<AnimatableNeutral> create() { return adoptRef(new AnimatableNeutral()); }
- virtual PassRefPtr<AnimatableValue> interpolateTo(const AnimatableValue* value, double fraction) const OVERRIDE
+ static PassRefPtrWillBeRawPtr<AnimatableNeutral> create() { return adoptRefWillBeNoop(new AnimatableNeutral()); }
+ virtual PassRefPtrWillBeRawPtr<AnimatableValue> interpolateTo(const AnimatableValue* value, double fraction) const OVERRIDE
{
ASSERT_NOT_REACHED();
- return 0;
+ return nullptr;
}
private:
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimatableNeutralTest.cpp b/chromium/third_party/WebKit/Source/core/animation/AnimatableNeutralTest.cpp
index dbf685ab8fd..755aa77e514 100644
--- a/chromium/third_party/WebKit/Source/core/animation/AnimatableNeutralTest.cpp
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimatableNeutralTest.cpp
@@ -45,13 +45,4 @@ TEST(AnimationAnimatableNeutralTest, Create)
EXPECT_TRUE(AnimatableValue::neutralValue());
}
-TEST(AnimationAnimatableNeutralTest, Add)
-{
- RefPtr<CSSValue> cssValue = CSSArrayFunctionValue::create();
- RefPtr<AnimatableValue> animatableUnknown = AnimatableUnknown::create(cssValue);
-
- EXPECT_EQ(cssValue, toAnimatableUnknown(AnimatableValue::add(animatableUnknown.get(), AnimatableValue::neutralValue()).get())->toCSSValue());
- EXPECT_EQ(cssValue, toAnimatableUnknown(AnimatableValue::add(AnimatableValue::neutralValue(), animatableUnknown.get()).get())->toCSSValue());
-}
-
}
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimatableRepeatable.cpp b/chromium/third_party/WebKit/Source/core/animation/AnimatableRepeatable.cpp
index a9f1ae6d982..2c2f63e4e8b 100644
--- a/chromium/third_party/WebKit/Source/core/animation/AnimatableRepeatable.cpp
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimatableRepeatable.cpp
@@ -31,63 +31,57 @@
#include "config.h"
#include "core/animation/AnimatableRepeatable.h"
-namespace {
+#include "wtf/MathExtras.h"
-size_t greatestCommonDivisor(size_t a, size_t b)
-{
- return b ? greatestCommonDivisor(b, a % b) : a;
-}
+namespace WebCore {
-size_t lowestCommonMultiple(size_t a, size_t b)
+bool AnimatableRepeatable::usesDefaultInterpolationWith(const AnimatableValue* value) const
{
- ASSERT(a && b);
- return a / greatestCommonDivisor(a, b) * b;
+ const WillBeHeapVector<RefPtrWillBeMember<AnimatableValue> >& fromValues = m_values;
+ const WillBeHeapVector<RefPtrWillBeMember<AnimatableValue> >& toValues = toAnimatableRepeatable(value)->m_values;
+ ASSERT(!fromValues.isEmpty() && !toValues.isEmpty());
+ size_t size = lowestCommonMultiple(fromValues.size(), toValues.size());
+ ASSERT(size > 0);
+ for (size_t i = 0; i < size; ++i) {
+ const AnimatableValue* from = fromValues[i % fromValues.size()].get();
+ const AnimatableValue* to = toValues[i % toValues.size()].get();
+ // Spec: If a pair of values cannot be interpolated, then the lists are not interpolable.
+ if (AnimatableValue::usesDefaultInterpolation(from, to))
+ return true;
+ }
+ return false;
}
-} // namespace
-
-namespace WebCore {
-
-bool AnimatableRepeatable::interpolateLists(const Vector<RefPtr<AnimatableValue> >& fromValues, const Vector<RefPtr<AnimatableValue> >& toValues, double fraction, Vector<RefPtr<AnimatableValue> >& interpolatedValues)
+bool AnimatableRepeatable::interpolateLists(const WillBeHeapVector<RefPtrWillBeMember<AnimatableValue> >& fromValues, const WillBeHeapVector<RefPtrWillBeMember<AnimatableValue> >& toValues, double fraction, WillBeHeapVector<RefPtrWillBeMember<AnimatableValue> >& interpolatedValues)
{
// Interpolation behaviour spec: http://www.w3.org/TR/css3-transitions/#animtype-repeatable-list
ASSERT(interpolatedValues.isEmpty());
ASSERT(!fromValues.isEmpty() && !toValues.isEmpty());
size_t size = lowestCommonMultiple(fromValues.size(), toValues.size());
+ ASSERT(size > 0);
for (size_t i = 0; i < size; ++i) {
const AnimatableValue* from = fromValues[i % fromValues.size()].get();
const AnimatableValue* to = toValues[i % toValues.size()].get();
// Spec: If a pair of values cannot be interpolated, then the lists are not interpolable.
- if (!from->usesNonDefaultInterpolationWith(to))
+ if (AnimatableValue::usesDefaultInterpolation(from, to))
return false;
interpolatedValues.append(interpolate(from, to, fraction));
}
return true;
}
-PassRefPtr<AnimatableValue> AnimatableRepeatable::interpolateTo(const AnimatableValue* value, double fraction) const
+PassRefPtrWillBeRawPtr<AnimatableValue> AnimatableRepeatable::interpolateTo(const AnimatableValue* value, double fraction) const
{
- Vector<RefPtr<AnimatableValue> > interpolatedValues;
+ WillBeHeapVector<RefPtrWillBeMember<AnimatableValue> > interpolatedValues;
bool success = interpolateLists(m_values, toAnimatableRepeatable(value)->m_values, fraction, interpolatedValues);
- return success ? create(interpolatedValues) : defaultInterpolateTo(this, value, fraction);
-}
-
-PassRefPtr<AnimatableValue> AnimatableRepeatable::addWith(const AnimatableValue* value) const
-{
- const Vector<RefPtr<AnimatableValue> >& otherValues = toAnimatableRepeatable(value)->m_values;
- ASSERT(!m_values.isEmpty() && !otherValues.isEmpty());
- Vector<RefPtr<AnimatableValue> > addedValues(lowestCommonMultiple(m_values.size(), otherValues.size()));
- for (size_t i = 0; i < addedValues.size(); ++i) {
- const AnimatableValue* left = m_values[i % m_values.size()].get();
- const AnimatableValue* right = otherValues[i % otherValues.size()].get();
- addedValues[i] = add(left, right);
- }
- return create(addedValues);
+ if (success)
+ return create(interpolatedValues);
+ return defaultInterpolateTo(this, value, fraction);
}
bool AnimatableRepeatable::equalTo(const AnimatableValue* value) const
{
- const Vector<RefPtr<AnimatableValue> >& otherValues = toAnimatableRepeatable(value)->m_values;
+ const WillBeHeapVector<RefPtrWillBeMember<AnimatableValue> >& otherValues = toAnimatableRepeatable(value)->m_values;
if (m_values.size() != otherValues.size())
return false;
for (size_t i = 0; i < m_values.size(); ++i) {
@@ -97,4 +91,10 @@ bool AnimatableRepeatable::equalTo(const AnimatableValue* value) const
return true;
}
+void AnimatableRepeatable::trace(Visitor* visitor)
+{
+ visitor->trace(m_values);
+ AnimatableValue::trace(visitor);
+}
+
} // namespace WebCore
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimatableRepeatable.h b/chromium/third_party/WebKit/Source/core/animation/AnimatableRepeatable.h
index b1c74949c11..317fbfc113f 100644
--- a/chromium/third_party/WebKit/Source/core/animation/AnimatableRepeatable.h
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimatableRepeatable.h
@@ -43,33 +43,36 @@ public:
virtual ~AnimatableRepeatable() { }
// This will consume the vector passed into it.
- static PassRefPtr<AnimatableRepeatable> create(Vector<RefPtr<AnimatableValue> >& values)
+ static PassRefPtrWillBeRawPtr<AnimatableRepeatable> create(WillBeHeapVector<RefPtrWillBeMember<AnimatableValue> >& values)
{
- return adoptRef(new AnimatableRepeatable(values));
+ return adoptRefWillBeNoop(new AnimatableRepeatable(values));
}
- const Vector<RefPtr<AnimatableValue> >& values() const { return m_values; }
+ const WillBeHeapVector<RefPtrWillBeMember<AnimatableValue> >& values() const { return m_values; }
+
+ virtual void trace(Visitor*) OVERRIDE;
protected:
AnimatableRepeatable()
{
}
- AnimatableRepeatable(Vector<RefPtr<AnimatableValue> >& values)
+ AnimatableRepeatable(WillBeHeapVector<RefPtrWillBeMember<AnimatableValue> >& values)
{
ASSERT(!values.isEmpty());
m_values.swap(values);
}
- static bool interpolateLists(const Vector<RefPtr<AnimatableValue> >& fromValues, const Vector<RefPtr<AnimatableValue> >& toValues, double fraction, Vector<RefPtr<AnimatableValue> >& interpolatedValues);
+ static bool interpolateLists(const WillBeHeapVector<RefPtrWillBeMember<AnimatableValue> >& fromValues, const WillBeHeapVector<RefPtrWillBeMember<AnimatableValue> >& toValues, double fraction, WillBeHeapVector<RefPtrWillBeMember<AnimatableValue> >& interpolatedValues);
+
+ virtual bool usesDefaultInterpolationWith(const AnimatableValue*) const OVERRIDE;
- Vector<RefPtr<AnimatableValue> > m_values;
+ WillBeHeapVector<RefPtrWillBeMember<AnimatableValue> > m_values;
private:
- virtual PassRefPtr<AnimatableValue> interpolateTo(const AnimatableValue*, double fraction) const OVERRIDE;
- virtual PassRefPtr<AnimatableValue> addWith(const AnimatableValue*) const OVERRIDE;
+ virtual PassRefPtrWillBeRawPtr<AnimatableValue> interpolateTo(const AnimatableValue*, double fraction) const OVERRIDE;
virtual AnimatableType type() const OVERRIDE { return TypeRepeatable; }
- virtual bool equalTo(const AnimatableValue*) const OVERRIDE;
+ virtual bool equalTo(const AnimatableValue*) const OVERRIDE FINAL;
};
DEFINE_TYPE_CASTS(AnimatableRepeatable, AnimatableValue, value, (value->isRepeatable() || value->isStrokeDasharrayList()), (value.isRepeatable() || value.isStrokeDasharrayList()));
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimatableSVGLength.cpp b/chromium/third_party/WebKit/Source/core/animation/AnimatableSVGLength.cpp
index 97f4158d0b3..829140e7b7c 100644
--- a/chromium/third_party/WebKit/Source/core/animation/AnimatableSVGLength.cpp
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimatableSVGLength.cpp
@@ -35,20 +35,14 @@
namespace WebCore {
-PassRefPtr<AnimatableValue> AnimatableSVGLength::interpolateTo(const AnimatableValue* value, double fraction) const
+PassRefPtrWillBeRawPtr<AnimatableValue> AnimatableSVGLength::interpolateTo(const AnimatableValue* value, double fraction) const
{
- return create(toAnimatableSVGLength(value)->toSVGLength().blend(m_length, narrowPrecisionToFloat(fraction)));
-}
-
-PassRefPtr<AnimatableValue> AnimatableSVGLength::addWith(const AnimatableValue* value) const
-{
- ASSERT_WITH_MESSAGE(false, "Web Animations not yet implemented: AnimatableSVGLength::addWith()");
- return defaultAddWith(this, value);
+ return create(toAnimatableSVGLength(value)->toSVGLength()->blend(m_length.get(), narrowPrecisionToFloat(fraction)));
}
bool AnimatableSVGLength::equalTo(const AnimatableValue* value) const
{
- return m_length == toAnimatableSVGLength(value)->m_length;
+ return *m_length == *toAnimatableSVGLength(value)->m_length;
}
} // namespace WebCore
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimatableSVGLength.h b/chromium/third_party/WebKit/Source/core/animation/AnimatableSVGLength.h
index 27dba9a48c1..5b7f7912bb3 100644
--- a/chromium/third_party/WebKit/Source/core/animation/AnimatableSVGLength.h
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimatableSVGLength.h
@@ -36,34 +36,35 @@
namespace WebCore {
-class AnimatableSVGLength: public AnimatableValue {
+class AnimatableSVGLength FINAL : public AnimatableValue {
public:
virtual ~AnimatableSVGLength() { }
- static PassRefPtr<AnimatableSVGLength> create(const SVGLength& length)
+ static PassRefPtrWillBeRawPtr<AnimatableSVGLength> create(PassRefPtr<SVGLength> length)
{
- return adoptRef(new AnimatableSVGLength(length));
+ return adoptRefWillBeNoop(new AnimatableSVGLength(length));
}
- const SVGLength& toSVGLength() const
+ SVGLength* toSVGLength() const
{
- return m_length;
+ return m_length.get();
}
+ virtual void trace(Visitor* visitor) OVERRIDE { AnimatableValue::trace(visitor); }
+
protected:
- virtual PassRefPtr<AnimatableValue> interpolateTo(const AnimatableValue*, double fraction) const OVERRIDE;
- virtual PassRefPtr<AnimatableValue> addWith(const AnimatableValue*) const OVERRIDE;
+ virtual PassRefPtrWillBeRawPtr<AnimatableValue> interpolateTo(const AnimatableValue*, double fraction) const OVERRIDE;
private:
- AnimatableSVGLength(const SVGLength& length)
+ AnimatableSVGLength(PassRefPtr<SVGLength> length)
: m_length(length)
{
}
- virtual AnimatableType type() const { return TypeSVGLength; }
+ virtual AnimatableType type() const OVERRIDE { return TypeSVGLength; }
virtual bool equalTo(const AnimatableValue*) const OVERRIDE;
- SVGLength m_length;
+ RefPtr<SVGLength> m_length;
};
DEFINE_ANIMATABLE_VALUE_TYPE_CASTS(AnimatableSVGLength, isSVGLength());
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimatableSVGPaint.cpp b/chromium/third_party/WebKit/Source/core/animation/AnimatableSVGPaint.cpp
index 784c9d32558..94eca3cd587 100644
--- a/chromium/third_party/WebKit/Source/core/animation/AnimatableSVGPaint.cpp
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimatableSVGPaint.cpp
@@ -33,32 +33,33 @@
namespace WebCore {
-PassRefPtr<AnimatableValue> AnimatableSVGPaint::interpolateTo(const AnimatableValue* value, double fraction) const
+bool AnimatableSVGPaint::usesDefaultInterpolationWith(const AnimatableValue* value) const
{
const AnimatableSVGPaint* svgPaint = toAnimatableSVGPaint(value);
- if (paintType() == SVGPaint::SVG_PAINTTYPE_RGBCOLOR && svgPaint->paintType() == SVGPaint::SVG_PAINTTYPE_RGBCOLOR) {
- ASSERT(uri().isNull());
- return AnimatableSVGPaint::create(SVGPaint::SVG_PAINTTYPE_RGBCOLOR, m_color.interpolateTo(svgPaint->m_color, fraction), String());
- }
- return defaultInterpolateTo(this, value, fraction);
+ return (paintType() != SVGPaint::SVG_PAINTTYPE_RGBCOLOR || svgPaint->paintType() != SVGPaint::SVG_PAINTTYPE_RGBCOLOR)
+ && (visitedLinkPaintType() != SVGPaint::SVG_PAINTTYPE_RGBCOLOR || svgPaint->visitedLinkPaintType() != SVGPaint::SVG_PAINTTYPE_RGBCOLOR);
}
-PassRefPtr<AnimatableValue> AnimatableSVGPaint::addWith(const AnimatableValue* value) const
+PassRefPtrWillBeRawPtr<AnimatableValue> AnimatableSVGPaint::interpolateTo(const AnimatableValue* value, double fraction) const
{
+ if (usesDefaultInterpolationWith(value))
+ return defaultInterpolateTo(this, value, fraction);
+
const AnimatableSVGPaint* svgPaint = toAnimatableSVGPaint(value);
- if (paintType() != SVGPaint::SVG_PAINTTYPE_RGBCOLOR || svgPaint->paintType() != SVGPaint::SVG_PAINTTYPE_RGBCOLOR) {
- ASSERT(uri().isNull());
- return AnimatableSVGPaint::create(SVGPaint::SVG_PAINTTYPE_RGBCOLOR, m_color.addWith(svgPaint->m_color), String());
- }
- return defaultAddWith(this, value);
+ RefPtrWillBeRawPtr<AnimatableColor> color = toAnimatableColor(AnimatableValue::interpolate(m_color.get(), svgPaint->m_color.get(), fraction).get());
+ if (fraction < 0.5)
+ return create(paintType(), visitedLinkPaintType(), color, uri(), visitedLinkURI());
+ return create(svgPaint->paintType(), svgPaint->visitedLinkPaintType(), color, svgPaint->uri(), svgPaint->visitedLinkURI());
}
bool AnimatableSVGPaint::equalTo(const AnimatableValue* value) const
{
const AnimatableSVGPaint* svgPaint = toAnimatableSVGPaint(value);
return paintType() == svgPaint->paintType()
+ && visitedLinkPaintType() == svgPaint->visitedLinkPaintType()
&& color() == svgPaint->color()
- && uri() == svgPaint->uri();
+ && uri() == svgPaint->uri()
+ && visitedLinkURI() == svgPaint->visitedLinkURI();
}
}
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimatableSVGPaint.h b/chromium/third_party/WebKit/Source/core/animation/AnimatableSVGPaint.h
index 93ebd2e8ca6..ff54142b43c 100644
--- a/chromium/third_party/WebKit/Source/core/animation/AnimatableSVGPaint.h
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimatableSVGPaint.h
@@ -37,38 +37,58 @@
namespace WebCore {
-class AnimatableSVGPaint : public AnimatableValue {
+class AnimatableSVGPaint FINAL : public AnimatableValue {
public:
virtual ~AnimatableSVGPaint() { }
- static PassRefPtr<AnimatableSVGPaint> create(SVGPaint::SVGPaintType type, const Color& color, const String& uri)
+ static PassRefPtrWillBeRawPtr<AnimatableSVGPaint> create(
+ SVGPaint::SVGPaintType type, SVGPaint::SVGPaintType visitedLinkType,
+ const Color& color, const Color& visitedLinkColor,
+ const String& uri, const String& visitedLinkURI)
{
- return create(type, AnimatableColorImpl(color), uri);
+ return create(type, visitedLinkType, AnimatableColor::create(color, visitedLinkColor), uri, visitedLinkURI);
}
- static PassRefPtr<AnimatableSVGPaint> create(SVGPaint::SVGPaintType type, const AnimatableColorImpl& color, const String& uri)
+ static PassRefPtrWillBeRawPtr<AnimatableSVGPaint> create(
+ SVGPaint::SVGPaintType type, SVGPaint::SVGPaintType visitedLinkType,
+ PassRefPtrWillBeRawPtr<AnimatableColor> color,
+ const String& uri, const String& visitedLinkURI)
{
- return adoptRef(new AnimatableSVGPaint(type, color, uri));
+ return adoptRefWillBeNoop(new AnimatableSVGPaint(type, visitedLinkType, color, uri, visitedLinkURI));
}
SVGPaint::SVGPaintType paintType() const { return m_type; };
- Color color() const { return m_color.toColor(); };
+ SVGPaint::SVGPaintType visitedLinkPaintType() const { return m_visitedLinkType; };
+ Color color() const { return m_color->color(); };
+ Color visitedLinkColor() const { return m_color->visitedLinkColor(); };
const String& uri() const { return m_uri; };
+ const String& visitedLinkURI() const { return m_visitedLinkURI; };
+
+ virtual void trace(Visitor* visitor) OVERRIDE
+ {
+ visitor->trace(m_color);
+ AnimatableValue::trace(visitor);
+ }
protected:
- virtual PassRefPtr<AnimatableValue> interpolateTo(const AnimatableValue*, double fraction) const OVERRIDE;
- virtual PassRefPtr<AnimatableValue> addWith(const AnimatableValue*) const OVERRIDE;
+ virtual PassRefPtrWillBeRawPtr<AnimatableValue> interpolateTo(const AnimatableValue*, double fraction) const OVERRIDE;
+ virtual bool usesDefaultInterpolationWith(const AnimatableValue*) const OVERRIDE;
private:
- AnimatableSVGPaint(SVGPaint::SVGPaintType type, const AnimatableColorImpl& color, const String& uri)
+ AnimatableSVGPaint(SVGPaint::SVGPaintType type, SVGPaint::SVGPaintType visitedLinkType, PassRefPtrWillBeRawPtr<AnimatableColor> color, const String& uri, const String& visitedLinkURI)
: m_type(type)
+ , m_visitedLinkType(visitedLinkType)
, m_color(color)
, m_uri(uri)
+ , m_visitedLinkURI(visitedLinkURI)
{
}
virtual AnimatableType type() const OVERRIDE { return TypeSVGPaint; }
virtual bool equalTo(const AnimatableValue*) const OVERRIDE;
SVGPaint::SVGPaintType m_type;
- AnimatableColorImpl m_color;
+ SVGPaint::SVGPaintType m_visitedLinkType;
+ // AnimatableColor includes a visited link color.
+ RefPtrWillBeMember<AnimatableColor> m_color;
String m_uri;
+ String m_visitedLinkURI;
};
DEFINE_ANIMATABLE_VALUE_TYPE_CASTS(AnimatableSVGPaint, isSVGPaint());
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimatableShadow.cpp b/chromium/third_party/WebKit/Source/core/animation/AnimatableShadow.cpp
index 4d1a847f319..63719bbe99a 100644
--- a/chromium/third_party/WebKit/Source/core/animation/AnimatableShadow.cpp
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimatableShadow.cpp
@@ -33,19 +33,12 @@
namespace WebCore {
-PassRefPtr<AnimatableValue> AnimatableShadow::interpolateTo(const AnimatableValue* value, double fraction) const
+PassRefPtrWillBeRawPtr<AnimatableValue> AnimatableShadow::interpolateTo(const AnimatableValue* value, double fraction) const
{
const AnimatableShadow* shadowList = toAnimatableShadow(value);
return AnimatableShadow::create(ShadowList::blend(m_shadowList.get(), shadowList->m_shadowList.get(), fraction));
}
-PassRefPtr<AnimatableValue> AnimatableShadow::addWith(const AnimatableValue* value) const
-{
- // FIXME: The spec doesn't specify anything for shadow in particular, but
- // the default behaviour is probably not what one would expect.
- return AnimatableValue::defaultAddWith(this, value);
-}
-
bool AnimatableShadow::equalTo(const AnimatableValue* value) const
{
const ShadowList* shadowList = toAnimatableShadow(value)->m_shadowList.get();
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimatableShadow.h b/chromium/third_party/WebKit/Source/core/animation/AnimatableShadow.h
index 23fb59b7a08..80a7cf51886 100644
--- a/chromium/third_party/WebKit/Source/core/animation/AnimatableShadow.h
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimatableShadow.h
@@ -36,18 +36,19 @@
namespace WebCore {
-class AnimatableShadow : public AnimatableValue {
+class AnimatableShadow FINAL : public AnimatableValue {
public:
virtual ~AnimatableShadow() { }
- static PassRefPtr<AnimatableShadow> create(PassRefPtr<ShadowList> shadowList)
+ static PassRefPtrWillBeRawPtr<AnimatableShadow> create(PassRefPtr<ShadowList> shadowList)
{
- return adoptRef(new AnimatableShadow(shadowList));
+ return adoptRefWillBeNoop(new AnimatableShadow(shadowList));
}
ShadowList* shadowList() const { return m_shadowList.get(); }
+ virtual void trace(Visitor* visitor) OVERRIDE { AnimatableValue::trace(visitor); }
+
protected:
- virtual PassRefPtr<AnimatableValue> interpolateTo(const AnimatableValue*, double fraction) const OVERRIDE;
- virtual PassRefPtr<AnimatableValue> addWith(const AnimatableValue*) const OVERRIDE;
+ virtual PassRefPtrWillBeRawPtr<AnimatableValue> interpolateTo(const AnimatableValue*, double fraction) const OVERRIDE;
private:
explicit AnimatableShadow(PassRefPtr<ShadowList> shadowList)
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimatableShapeValue.cpp b/chromium/third_party/WebKit/Source/core/animation/AnimatableShapeValue.cpp
index 9b17295c273..2e71e0dc88a 100644
--- a/chromium/third_party/WebKit/Source/core/animation/AnimatableShapeValue.cpp
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimatableShapeValue.cpp
@@ -33,20 +33,30 @@
namespace WebCore {
-PassRefPtr<AnimatableValue> AnimatableShapeValue::interpolateTo(const AnimatableValue* value, double fraction) const
+bool AnimatableShapeValue::usesDefaultInterpolationWith(const AnimatableValue* value) const
{
const AnimatableShapeValue* shapeValue = toAnimatableShapeValue(value);
- if (m_shape->type() != ShapeValue::Shape || shapeValue->m_shape->type() != ShapeValue::Shape)
- return defaultInterpolateTo(this, value, fraction);
+ if (m_shape->type() != ShapeValue::Shape
+ || shapeValue->m_shape->type() != ShapeValue::Shape
+ || m_shape->cssBox() != shapeValue->m_shape->cssBox())
+ return true;
const BasicShape* fromShape = this->m_shape->shape();
const BasicShape* toShape = shapeValue->m_shape->shape();
- if (!fromShape->canBlend(toShape))
+ return !fromShape->canBlend(toShape);
+}
+
+PassRefPtrWillBeRawPtr<AnimatableValue> AnimatableShapeValue::interpolateTo(const AnimatableValue* value, double fraction) const
+{
+ if (usesDefaultInterpolationWith(value))
return defaultInterpolateTo(this, value, fraction);
- return AnimatableShapeValue::create(ShapeValue::createShapeValue(toShape->blend(fromShape, fraction)).get());
+ const AnimatableShapeValue* shapeValue = toAnimatableShapeValue(value);
+ const BasicShape* fromShape = this->m_shape->shape();
+ const BasicShape* toShape = shapeValue->m_shape->shape();
+ return AnimatableShapeValue::create(ShapeValue::createShapeValue(toShape->blend(fromShape, fraction), shapeValue->m_shape->cssBox()).get());
}
bool AnimatableShapeValue::equalTo(const AnimatableValue* value) const
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimatableShapeValue.h b/chromium/third_party/WebKit/Source/core/animation/AnimatableShapeValue.h
index 1d5382b0548..decc6f33f03 100644
--- a/chromium/third_party/WebKit/Source/core/animation/AnimatableShapeValue.h
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimatableShapeValue.h
@@ -36,17 +36,20 @@
namespace WebCore {
-class AnimatableShapeValue : public AnimatableValue {
+class AnimatableShapeValue FINAL : public AnimatableValue {
public:
virtual ~AnimatableShapeValue() { }
- static PassRefPtr<AnimatableShapeValue> create(ShapeValue* shape)
+ static PassRefPtrWillBeRawPtr<AnimatableShapeValue> create(ShapeValue* shape)
{
- return adoptRef(new AnimatableShapeValue(shape));
+ return adoptRefWillBeNoop(new AnimatableShapeValue(shape));
}
ShapeValue* shapeValue() const { return m_shape.get(); }
+ virtual void trace(Visitor* visitor) OVERRIDE { AnimatableValue::trace(visitor); }
+
protected:
- virtual PassRefPtr<AnimatableValue> interpolateTo(const AnimatableValue*, double fraction) const OVERRIDE;
+ virtual PassRefPtrWillBeRawPtr<AnimatableValue> interpolateTo(const AnimatableValue*, double fraction) const OVERRIDE;
+ virtual bool usesDefaultInterpolationWith(const AnimatableValue*) const OVERRIDE;
private:
AnimatableShapeValue(ShapeValue* shape)
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimatableStrokeDasharrayList.cpp b/chromium/third_party/WebKit/Source/core/animation/AnimatableStrokeDasharrayList.cpp
index b8951cc4cad..f81e3513a1e 100644
--- a/chromium/third_party/WebKit/Source/core/animation/AnimatableStrokeDasharrayList.cpp
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimatableStrokeDasharrayList.cpp
@@ -36,27 +36,36 @@
namespace WebCore {
-AnimatableStrokeDasharrayList::AnimatableStrokeDasharrayList(const Vector<SVGLength>& lengths)
+AnimatableStrokeDasharrayList::AnimatableStrokeDasharrayList(PassRefPtr<SVGLengthList> passLengths)
{
- for (size_t i = 0; i < lengths.size(); ++i)
- m_values.append(AnimatableSVGLength::create(lengths[i]));
+ RefPtr<SVGLengthList> lengths = passLengths;
+ SVGLengthList::ConstIterator it = lengths->begin();
+ SVGLengthList::ConstIterator itEnd = lengths->end();
+ for (; it != itEnd; ++it)
+ m_values.append(AnimatableSVGLength::create(*it));
}
-Vector<SVGLength> AnimatableStrokeDasharrayList::toSVGLengthVector() const
+PassRefPtr<SVGLengthList> AnimatableStrokeDasharrayList::toSVGLengthList() const
{
- Vector<SVGLength> lengths(m_values.size());
+ RefPtr<SVGLengthList> lengths = SVGLengthList::create();
for (size_t i = 0; i < m_values.size(); ++i) {
- lengths[i] = toAnimatableSVGLength(m_values[i].get())->toSVGLength();
- if (lengths[i].valueInSpecifiedUnits() < 0)
- lengths[i].setValueInSpecifiedUnits(0);
+ RefPtr<SVGLength> length = toAnimatableSVGLength(m_values[i].get())->toSVGLength()->clone();
+ if (length->valueInSpecifiedUnits() < 0)
+ length->setValueInSpecifiedUnits(0);
+ lengths->append(length);
}
- return lengths;
+ return lengths.release();
}
-PassRefPtr<AnimatableValue> AnimatableStrokeDasharrayList::interpolateTo(const AnimatableValue* value, double fraction) const
+bool AnimatableStrokeDasharrayList::usesDefaultInterpolationWith(const AnimatableValue* value) const
{
- Vector<RefPtr<AnimatableValue> > from = m_values;
- Vector<RefPtr<AnimatableValue> > to = toAnimatableStrokeDasharrayList(value)->m_values;
+ return false;
+}
+
+PassRefPtrWillBeRawPtr<AnimatableValue> AnimatableStrokeDasharrayList::interpolateTo(const AnimatableValue* value, double fraction) const
+{
+ WillBeHeapVector<RefPtrWillBeMember<AnimatableValue> > from = m_values;
+ WillBeHeapVector<RefPtrWillBeMember<AnimatableValue> > to = toAnimatableStrokeDasharrayList(value)->m_values;
// The spec states that if the sum of all values is zero, this should be
// treated like a value of 'none', which means that a solid line is drawn.
@@ -66,12 +75,7 @@ PassRefPtr<AnimatableValue> AnimatableStrokeDasharrayList::interpolateTo(const A
if (from.isEmpty() && to.isEmpty())
return takeConstRef(this);
if (from.isEmpty() || to.isEmpty()) {
- DEFINE_STATIC_REF(AnimatableSVGLength, zeroPixels, 0);
- if (!zeroPixels) {
- SVGLength length;
- length.newValueSpecifiedUnits(LengthTypePX, 0, IGNORE_EXCEPTION);
- zeroPixels = AnimatableSVGLength::create(length).leakRef();
- }
+ DEFINE_STATIC_REF_WILL_BE_PERSISTENT(AnimatableSVGLength, zeroPixels, (AnimatableSVGLength::create(SVGLength::create())));
if (from.isEmpty()) {
from.append(zeroPixels);
from.append(zeroPixels);
@@ -82,10 +86,15 @@ PassRefPtr<AnimatableValue> AnimatableStrokeDasharrayList::interpolateTo(const A
}
}
- Vector<RefPtr<AnimatableValue> > interpolatedValues;
+ WillBeHeapVector<RefPtrWillBeMember<AnimatableValue> > interpolatedValues;
bool success = interpolateLists(from, to, fraction, interpolatedValues);
ASSERT_UNUSED(success, success);
- return adoptRef(new AnimatableStrokeDasharrayList(interpolatedValues));
+ return adoptRefWillBeNoop(new AnimatableStrokeDasharrayList(interpolatedValues));
+}
+
+void AnimatableStrokeDasharrayList::trace(Visitor* visitor)
+{
+ AnimatableRepeatable::trace(visitor);
}
} // namespace WebCore
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimatableStrokeDasharrayList.h b/chromium/third_party/WebKit/Source/core/animation/AnimatableStrokeDasharrayList.h
index d19b2e017ac..c7f5d8fafd7 100644
--- a/chromium/third_party/WebKit/Source/core/animation/AnimatableStrokeDasharrayList.h
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimatableStrokeDasharrayList.h
@@ -32,33 +32,36 @@
#define AnimatableStrokeDasharrayList_h
#include "core/animation/AnimatableRepeatable.h"
-#include "core/svg/SVGLength.h"
+#include "core/svg/SVGLengthList.h"
namespace WebCore {
-class AnimatableStrokeDasharrayList: public AnimatableRepeatable {
+class AnimatableStrokeDasharrayList FINAL : public AnimatableRepeatable {
public:
virtual ~AnimatableStrokeDasharrayList() { }
- static PassRefPtr<AnimatableStrokeDasharrayList> create(const Vector<SVGLength>& lengths)
+ static PassRefPtrWillBeRawPtr<AnimatableStrokeDasharrayList> create(PassRefPtr<SVGLengthList> lengths)
{
- return adoptRef(new AnimatableStrokeDasharrayList(lengths));
+ return adoptRefWillBeNoop(new AnimatableStrokeDasharrayList(lengths));
}
- Vector<SVGLength> toSVGLengthVector() const;
+ PassRefPtr<SVGLengthList> toSVGLengthList() const;
+
+ virtual void trace(Visitor*) OVERRIDE;
protected:
- virtual PassRefPtr<AnimatableValue> interpolateTo(const AnimatableValue*, double fraction) const OVERRIDE;
+ virtual PassRefPtrWillBeRawPtr<AnimatableValue> interpolateTo(const AnimatableValue*, double fraction) const OVERRIDE;
+ virtual bool usesDefaultInterpolationWith(const AnimatableValue*) const OVERRIDE;
private:
- AnimatableStrokeDasharrayList(const Vector<SVGLength>&);
+ AnimatableStrokeDasharrayList(PassRefPtr<SVGLengthList>);
// This will consume the vector passed into it.
- AnimatableStrokeDasharrayList(Vector<RefPtr<AnimatableValue> >& values)
+ AnimatableStrokeDasharrayList(WillBeHeapVector<RefPtrWillBeMember<AnimatableValue> >& values)
: AnimatableRepeatable(values)
{
}
- virtual AnimatableType type() const { return TypeStrokeDasharrayList; }
+ virtual AnimatableType type() const OVERRIDE { return TypeStrokeDasharrayList; }
};
DEFINE_ANIMATABLE_VALUE_TYPE_CASTS(AnimatableStrokeDasharrayList, isStrokeDasharrayList());
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimatableStrokeDasharrayListTest.cpp b/chromium/third_party/WebKit/Source/core/animation/AnimatableStrokeDasharrayListTest.cpp
index 6a2756d2504..97f3330fcce 100644
--- a/chromium/third_party/WebKit/Source/core/animation/AnimatableStrokeDasharrayListTest.cpp
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimatableStrokeDasharrayListTest.cpp
@@ -39,21 +39,29 @@ using namespace WebCore;
namespace {
+PassRefPtr<SVGLengthList> createSVGLengthList(size_t length)
+{
+ RefPtr<SVGLengthList> list = SVGLengthList::create();
+ for (size_t i = 0; i < length; ++i)
+ list->append(SVGLength::create());
+ return list.release();
+}
+
TEST(AnimationAnimatableStrokeDasharrayListTest, EqualTo)
{
- Vector<SVGLength> vectorA(4);
- Vector<SVGLength> vectorB(4);
- RefPtr<AnimatableStrokeDasharrayList> listA = AnimatableStrokeDasharrayList::create(vectorA);
- RefPtr<AnimatableStrokeDasharrayList> listB = AnimatableStrokeDasharrayList::create(vectorB);
+ RefPtr<SVGLengthList> svgListA = createSVGLengthList(4);
+ RefPtr<SVGLengthList> svgListB = createSVGLengthList(4);
+ RefPtrWillBeRawPtr<AnimatableStrokeDasharrayList> listA = AnimatableStrokeDasharrayList::create(svgListA);
+ RefPtrWillBeRawPtr<AnimatableStrokeDasharrayList> listB = AnimatableStrokeDasharrayList::create(svgListB);
EXPECT_TRUE(listA->equals(listB.get()));
TrackExceptionState exceptionState;
- vectorB[3].newValueSpecifiedUnits(LengthTypePX, 50, exceptionState);
- listB = AnimatableStrokeDasharrayList::create(vectorB);
+ svgListB->at(3)->newValueSpecifiedUnits(LengthTypePX, 50);
+ listB = AnimatableStrokeDasharrayList::create(svgListB);
EXPECT_FALSE(listA->equals(listB.get()));
- vectorB = Vector<SVGLength>(5);
- listB = AnimatableStrokeDasharrayList::create(vectorB);
+ svgListB = createSVGLengthList(5);
+ listB = AnimatableStrokeDasharrayList::create(svgListB);
EXPECT_FALSE(listA->equals(listB.get()));
}
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimatableTransform.cpp b/chromium/third_party/WebKit/Source/core/animation/AnimatableTransform.cpp
index 542d8c315b0..98ea3e19930 100644
--- a/chromium/third_party/WebKit/Source/core/animation/AnimatableTransform.cpp
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimatableTransform.cpp
@@ -33,23 +33,17 @@
namespace WebCore {
-PassRefPtr<AnimatableTransform> AnimatableTransform::create(const TransformOperations& transform)
+PassRefPtrWillBeRawPtr<AnimatableTransform> AnimatableTransform::create(const TransformOperations& transform)
{
- return adoptRef(new AnimatableTransform(transform));
+ return adoptRefWillBeNoop(new AnimatableTransform(transform));
}
-PassRefPtr<AnimatableValue> AnimatableTransform::interpolateTo(const AnimatableValue* value, double fraction) const
+PassRefPtrWillBeRawPtr<AnimatableValue> AnimatableTransform::interpolateTo(const AnimatableValue* value, double fraction) const
{
const AnimatableTransform* transform = toAnimatableTransform(value);
return AnimatableTransform::create(transform->m_transform.blend(m_transform, fraction));
}
-PassRefPtr<AnimatableValue> AnimatableTransform::addWith(const AnimatableValue* value) const
-{
- const AnimatableTransform* transform = toAnimatableTransform(value);
- return AnimatableTransform::create(m_transform.add(transform->m_transform));
-}
-
bool AnimatableTransform::equalTo(const AnimatableValue* value) const
{
return m_transform == toAnimatableTransform(value)->m_transform;
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimatableTransform.h b/chromium/third_party/WebKit/Source/core/animation/AnimatableTransform.h
index 7fa85323fbc..51896af426b 100644
--- a/chromium/third_party/WebKit/Source/core/animation/AnimatableTransform.h
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimatableTransform.h
@@ -36,18 +36,19 @@
namespace WebCore {
-class AnimatableTransform : public AnimatableValue {
+class AnimatableTransform FINAL : public AnimatableValue {
public:
virtual ~AnimatableTransform() { }
- static PassRefPtr<AnimatableTransform> create(const TransformOperations&);
+ static PassRefPtrWillBeRawPtr<AnimatableTransform> create(const TransformOperations&);
const TransformOperations& transformOperations() const
{
return m_transform;
}
+ virtual void trace(Visitor* visitor) OVERRIDE { AnimatableValue::trace(visitor); }
+
protected:
- virtual PassRefPtr<AnimatableValue> interpolateTo(const AnimatableValue*, double fraction) const OVERRIDE;
- virtual PassRefPtr<AnimatableValue> addWith(const AnimatableValue*) const OVERRIDE;
+ virtual PassRefPtrWillBeRawPtr<AnimatableValue> interpolateTo(const AnimatableValue*, double fraction) const OVERRIDE;
private:
explicit AnimatableTransform(const TransformOperations& transform)
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimatableUnknown.h b/chromium/third_party/WebKit/Source/core/animation/AnimatableUnknown.h
index 43be1c8568c..820c656ef6d 100644
--- a/chromium/third_party/WebKit/Source/core/animation/AnimatableUnknown.h
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimatableUnknown.h
@@ -31,36 +31,44 @@
#ifndef AnimatableUnknown_h
#define AnimatableUnknown_h
-#include "CSSValueKeywords.h"
+#include "core/CSSValueKeywords.h"
#include "core/animation/AnimatableValue.h"
#include "core/css/CSSValuePool.h"
namespace WebCore {
-class AnimatableUnknown : public AnimatableValue {
+class AnimatableUnknown FINAL : public AnimatableValue {
public:
virtual ~AnimatableUnknown() { }
- static PassRefPtr<AnimatableUnknown> create(PassRefPtr<CSSValue> value)
+ static PassRefPtrWillBeRawPtr<AnimatableUnknown> create(PassRefPtrWillBeRawPtr<CSSValue> value)
{
- return adoptRef(new AnimatableUnknown(value));
+ return adoptRefWillBeNoop(new AnimatableUnknown(value));
}
- static PassRefPtr<AnimatableUnknown> create(CSSValueID value)
+ static PassRefPtrWillBeRawPtr<AnimatableUnknown> create(CSSValueID value)
{
- return adoptRef(new AnimatableUnknown(cssValuePool().createIdentifierValue(value)));
+ return adoptRefWillBeNoop(new AnimatableUnknown(cssValuePool().createIdentifierValue(value)));
}
- PassRefPtr<CSSValue> toCSSValue() const { return m_value; }
+ PassRefPtrWillBeRawPtr<CSSValue> toCSSValue() const { return m_value; }
CSSValueID toCSSValueID() const { return toCSSPrimitiveValue(m_value.get())->getValueID(); }
+ virtual void trace(Visitor* visitor) OVERRIDE
+ {
+ visitor->trace(m_value);
+ AnimatableValue::trace(visitor);
+ }
+
protected:
- virtual PassRefPtr<AnimatableValue> interpolateTo(const AnimatableValue* value, double fraction) const OVERRIDE
+ virtual PassRefPtrWillBeRawPtr<AnimatableValue> interpolateTo(const AnimatableValue* value, double fraction) const OVERRIDE
{
return defaultInterpolateTo(this, value, fraction);
}
+ virtual bool usesDefaultInterpolationWith(const AnimatableValue*) const OVERRIDE { return true; }
+
private:
- explicit AnimatableUnknown(PassRefPtr<CSSValue> value)
+ explicit AnimatableUnknown(PassRefPtrWillBeRawPtr<CSSValue> value)
: m_value(value)
{
ASSERT(m_value);
@@ -68,7 +76,7 @@ private:
virtual AnimatableType type() const OVERRIDE { return TypeUnknown; }
virtual bool equalTo(const AnimatableValue*) const OVERRIDE;
- const RefPtr<CSSValue> m_value;
+ const RefPtrWillBeMember<CSSValue> m_value;
};
DEFINE_ANIMATABLE_VALUE_TYPE_CASTS(AnimatableUnknown, isUnknown());
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimatableUnknownTest.cpp b/chromium/third_party/WebKit/Source/core/animation/AnimatableUnknownTest.cpp
index 5ca17607108..ad40dd76e57 100644
--- a/chromium/third_party/WebKit/Source/core/animation/AnimatableUnknownTest.cpp
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimatableUnknownTest.cpp
@@ -51,11 +51,10 @@ protected:
otherAnimatableUnknown = AnimatableUnknown::create(otherCSSValue);
}
- RefPtr<CSSValue> cssValue;
- RefPtr<AnimatableValue> animatableUnknown;
-
- RefPtr<CSSValue> otherCSSValue;
- RefPtr<AnimatableValue> otherAnimatableUnknown;
+ RefPtrWillBePersistent<CSSValue> cssValue;
+ RefPtrWillBePersistent<AnimatableValue> animatableUnknown;
+ RefPtrWillBePersistent<CSSValue> otherCSSValue;
+ RefPtrWillBePersistent<AnimatableValue> otherAnimatableUnknown;
};
TEST_F(AnimationAnimatableUnknownTest, Create)
@@ -83,10 +82,4 @@ TEST_F(AnimationAnimatableUnknownTest, Interpolate)
EXPECT_EQ(cssValue, toAnimatableUnknown(AnimatableValue::interpolate(otherAnimatableUnknown.get(), animatableUnknown.get(), 1).get())->toCSSValue());
}
-TEST_F(AnimationAnimatableUnknownTest, Add)
-{
- EXPECT_EQ(otherCSSValue, toAnimatableUnknown(AnimatableValue::add(animatableUnknown.get(), otherAnimatableUnknown.get()).get())->toCSSValue());
- EXPECT_EQ(cssValue, toAnimatableUnknown(AnimatableValue::add(otherAnimatableUnknown.get(), animatableUnknown.get()).get())->toCSSValue());
-}
-
}
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimatableValue.cpp b/chromium/third_party/WebKit/Source/core/animation/AnimatableValue.cpp
index 1c9d1751ca0..af0aec9ac4a 100644
--- a/chromium/third_party/WebKit/Source/core/animation/AnimatableValue.cpp
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimatableValue.cpp
@@ -34,15 +34,21 @@
#include "wtf/StdLibExtras.h"
#include <algorithm>
+namespace {
+
+const double defaultDistance = 1;
+
+} // namespace
+
namespace WebCore {
const AnimatableValue* AnimatableValue::neutralValue()
{
- DEFINE_STATIC_REF(AnimatableNeutral, neutralSentinelValue, (AnimatableNeutral::create()));
+ DEFINE_STATIC_REF_WILL_BE_PERSISTENT(AnimatableNeutral, neutralSentinelValue, (AnimatableNeutral::create()));
return neutralSentinelValue;
}
-PassRefPtr<AnimatableValue> AnimatableValue::interpolate(const AnimatableValue* left, const AnimatableValue* right, double fraction)
+PassRefPtrWillBeRawPtr<AnimatableValue> AnimatableValue::interpolate(const AnimatableValue* left, const AnimatableValue* right, double fraction)
{
ASSERT(left);
ASSERT(right);
@@ -55,25 +61,20 @@ PassRefPtr<AnimatableValue> AnimatableValue::interpolate(const AnimatableValue*
return defaultInterpolateTo(left, right, fraction);
}
-PassRefPtr<AnimatableValue> AnimatableValue::add(const AnimatableValue* left, const AnimatableValue* right)
+double AnimatableValue::distance(const AnimatableValue* left, const AnimatableValue* right)
{
ASSERT(left);
ASSERT(right);
- if (left->isNeutral())
- return takeConstRef(right);
- if (right->isNeutral())
- return takeConstRef(left);
-
if (left->isSameType(right))
- return left->addWith(right);
+ return left->distanceTo(right);
- return defaultAddWith(left, right);
+ return defaultDistance;
}
-PassRefPtr<AnimatableValue> AnimatableValue::addWith(const AnimatableValue* value) const
+double AnimatableValue::distanceTo(const AnimatableValue*) const
{
- return defaultAddWith(this, value);
+ return defaultDistance;
}
} // namespace WebCore
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimatableValue.h b/chromium/third_party/WebKit/Source/core/animation/AnimatableValue.h
index 2e52c321e95..2306142cc1c 100644
--- a/chromium/third_party/WebKit/Source/core/animation/AnimatableValue.h
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimatableValue.h
@@ -32,19 +32,23 @@
#define AnimatableValue_h
#include "core/css/CSSValue.h"
+#include "platform/heap/Handle.h"
#include "wtf/RefCounted.h"
namespace WebCore {
-class AnimatableValue : public RefCounted<AnimatableValue> {
+class AnimatableValue : public RefCountedWillBeGarbageCollectedFinalized<AnimatableValue> {
public:
virtual ~AnimatableValue() { }
static const AnimatableValue* neutralValue();
- static PassRefPtr<AnimatableValue> interpolate(const AnimatableValue*, const AnimatableValue*, double fraction);
- // For noncommutative values read add(A, B) to mean the value A with B composed onto it.
- static PassRefPtr<AnimatableValue> add(const AnimatableValue*, const AnimatableValue*);
+ static PassRefPtrWillBeRawPtr<AnimatableValue> interpolate(const AnimatableValue*, const AnimatableValue*, double fraction);
+ static double distance(const AnimatableValue* from, const AnimatableValue* to);
+ static bool usesDefaultInterpolation(const AnimatableValue* from, const AnimatableValue* to)
+ {
+ return !from->isSameType(to) || from->usesDefaultInterpolationWith(to);
+ }
bool equals(const AnimatableValue* value) const
{
@@ -64,6 +68,7 @@ public:
bool isLengthBox() const { return type() == TypeLengthBox; }
bool isLengthBoxAndBool() const { return type() == TypeLengthBoxAndBool; }
bool isLengthPoint() const { return type() == TypeLengthPoint; }
+ bool isLengthPoint3D() const { return type() == TypeLengthPoint3D; }
bool isLengthSize() const { return type() == TypeLengthSize; }
bool isNeutral() const { return type() == TypeNeutral; }
bool isRepeatable() const { return type() == TypeRepeatable; }
@@ -82,10 +87,7 @@ public:
return value->type() == type();
}
- bool usesNonDefaultInterpolationWith(const AnimatableValue* value) const
- {
- return isSameType(value) && !isUnknown();
- }
+ virtual void trace(Visitor*) { }
protected:
enum AnimatableType {
@@ -98,6 +100,7 @@ protected:
TypeLengthBox,
TypeLengthBoxAndBool,
TypeLengthPoint,
+ TypeLengthPoint3D,
TypeLengthSize,
TypeNeutral,
TypeRepeatable,
@@ -111,20 +114,21 @@ protected:
TypeVisibility,
};
- virtual PassRefPtr<AnimatableValue> interpolateTo(const AnimatableValue*, double fraction) const = 0;
- static PassRefPtr<AnimatableValue> defaultInterpolateTo(const AnimatableValue* left, const AnimatableValue* right, double fraction) { return takeConstRef((fraction < 0.5) ? left : right); }
-
- // For noncommutative values read A->addWith(B) to mean the value A with B composed onto it.
- virtual PassRefPtr<AnimatableValue> addWith(const AnimatableValue*) const;
- static PassRefPtr<AnimatableValue> defaultAddWith(const AnimatableValue* left, const AnimatableValue* right) { return takeConstRef(right); }
+ virtual bool usesDefaultInterpolationWith(const AnimatableValue* value) const { return false; }
+ virtual PassRefPtrWillBeRawPtr<AnimatableValue> interpolateTo(const AnimatableValue*, double fraction) const = 0;
+ static PassRefPtrWillBeRawPtr<AnimatableValue> defaultInterpolateTo(const AnimatableValue* left, const AnimatableValue* right, double fraction) { return takeConstRef((fraction < 0.5) ? left : right); }
template <class T>
- static PassRefPtr<T> takeConstRef(const T* value) { return PassRefPtr<T>(const_cast<T*>(value)); }
+ static PassRefPtrWillBeRawPtr<T> takeConstRef(const T* value) { return PassRefPtrWillBeRawPtr<T>(const_cast<T*>(value)); }
private:
virtual AnimatableType type() const = 0;
// Implementations can assume that the object being compared has the same type as the object this is called on
virtual bool equalTo(const AnimatableValue*) const = 0;
+
+ virtual double distanceTo(const AnimatableValue*) const;
+
+ template <class Keyframe> friend class KeyframeEffectModel;
};
#define DEFINE_ANIMATABLE_VALUE_TYPE_CASTS(thisType, predicate) \
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimatableValueKeyframe.cpp b/chromium/third_party/WebKit/Source/core/animation/AnimatableValueKeyframe.cpp
new file mode 100644
index 00000000000..43e9bfdee32
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimatableValueKeyframe.cpp
@@ -0,0 +1,80 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "config.h"
+#include "core/animation/AnimatableValueKeyframe.h"
+
+#include "core/animation/interpolation/LegacyStyleInterpolation.h"
+
+namespace WebCore {
+
+AnimatableValueKeyframe::AnimatableValueKeyframe(const AnimatableValueKeyframe& copyFrom)
+ : Keyframe(copyFrom.m_offset, copyFrom.m_composite, copyFrom.m_easing)
+{
+ for (PropertyValueMap::const_iterator iter = copyFrom.m_propertyValues.begin(); iter != copyFrom.m_propertyValues.end(); ++iter)
+ setPropertyValue(iter->key, iter->value.get());
+}
+
+PropertySet AnimatableValueKeyframe::properties() const
+{
+ // This is not used in time-critical code, so we probably don't need to
+ // worry about caching this result.
+ PropertySet properties;
+ for (PropertyValueMap::const_iterator iter = m_propertyValues.begin(); iter != m_propertyValues.end(); ++iter)
+ properties.add(*iter.keys());
+ return properties;
+}
+
+PassRefPtrWillBeRawPtr<Keyframe> AnimatableValueKeyframe::clone() const
+{
+ return adoptRefWillBeNoop(new AnimatableValueKeyframe(*this));
+}
+
+PassOwnPtrWillBeRawPtr<Keyframe::PropertySpecificKeyframe> AnimatableValueKeyframe::createPropertySpecificKeyframe(CSSPropertyID property) const
+{
+ return adoptPtrWillBeNoop(new PropertySpecificKeyframe(offset(), easing(), propertyValue(property), composite()));
+}
+
+void AnimatableValueKeyframe::trace(Visitor* visitor)
+{
+ visitor->trace(m_propertyValues);
+ Keyframe::trace(visitor);
+}
+
+AnimatableValueKeyframe::PropertySpecificKeyframe::PropertySpecificKeyframe(double offset, PassRefPtr<TimingFunction> easing, const AnimatableValue* value, AnimationEffect::CompositeOperation op)
+ : Keyframe::PropertySpecificKeyframe(offset, easing, op)
+ , m_value(const_cast<AnimatableValue*>(value))
+{ }
+
+AnimatableValueKeyframe::PropertySpecificKeyframe::PropertySpecificKeyframe(double offset, PassRefPtr<TimingFunction> easing, PassRefPtrWillBeRawPtr<AnimatableValue> value)
+ : Keyframe::PropertySpecificKeyframe(offset, easing, AnimationEffect::CompositeReplace)
+ , m_value(value)
+{
+ ASSERT(!isNull(m_offset));
+}
+
+PassOwnPtrWillBeRawPtr<Keyframe::PropertySpecificKeyframe> AnimatableValueKeyframe::PropertySpecificKeyframe::cloneWithOffset(double offset) const
+{
+ Keyframe::PropertySpecificKeyframe* theClone = new PropertySpecificKeyframe(offset, m_easing, m_value);
+ return adoptPtrWillBeNoop(theClone);
+}
+
+PassRefPtrWillBeRawPtr<Interpolation> AnimatableValueKeyframe::PropertySpecificKeyframe::createInterpolation(CSSPropertyID property, Keyframe::PropertySpecificKeyframe* end, Element*) const
+{
+ AnimatableValuePropertySpecificKeyframe* to = toAnimatableValuePropertySpecificKeyframe(end);
+ return LegacyStyleInterpolation::create(value(), to->value(), property);
+}
+
+PassOwnPtrWillBeRawPtr<Keyframe::PropertySpecificKeyframe> AnimatableValueKeyframe::PropertySpecificKeyframe::neutralKeyframe(double offset, PassRefPtr<TimingFunction> easing) const
+{
+ return adoptPtrWillBeNoop(new AnimatableValueKeyframe::PropertySpecificKeyframe(offset, easing, AnimatableValue::neutralValue(), AnimationEffect::CompositeAdd));
+}
+
+void AnimatableValueKeyframe::PropertySpecificKeyframe::trace(Visitor* visitor)
+{
+ visitor->trace(m_value);
+ Keyframe::PropertySpecificKeyframe::trace(visitor);
+}
+
+}
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimatableValueKeyframe.h b/chromium/third_party/WebKit/Source/core/animation/AnimatableValueKeyframe.h
new file mode 100644
index 00000000000..c3fd15584e9
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimatableValueKeyframe.h
@@ -0,0 +1,75 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef AnimatableValueKeyframe_h
+#define AnimatableValueKeyframe_h
+
+#include "core/animation/AnimatableValue.h"
+#include "core/animation/Keyframe.h"
+
+namespace WebCore {
+
+class AnimatableValueKeyframe : public Keyframe {
+public:
+ static PassRefPtrWillBeRawPtr<AnimatableValueKeyframe> create()
+ {
+ return adoptRefWillBeNoop(new AnimatableValueKeyframe);
+ }
+ void setPropertyValue(CSSPropertyID property, PassRefPtrWillBeRawPtr<AnimatableValue> value)
+ {
+ m_propertyValues.add(property, value);
+ }
+ void clearPropertyValue(CSSPropertyID property) { m_propertyValues.remove(property); }
+ AnimatableValue* propertyValue(CSSPropertyID property) const
+ {
+ ASSERT(m_propertyValues.contains(property));
+ return m_propertyValues.get(property);
+ }
+ virtual PropertySet properties() const OVERRIDE;
+
+ virtual void trace(Visitor*) OVERRIDE;
+
+ class PropertySpecificKeyframe : public Keyframe::PropertySpecificKeyframe {
+ public:
+ PropertySpecificKeyframe(double offset, PassRefPtr<TimingFunction> easing, const AnimatableValue*, AnimationEffect::CompositeOperation);
+
+ AnimatableValue* value() const { return m_value.get(); }
+ virtual const PassRefPtrWillBeRawPtr<AnimatableValue> getAnimatableValue() const OVERRIDE FINAL { return m_value; }
+
+ virtual PassOwnPtrWillBeRawPtr<Keyframe::PropertySpecificKeyframe> neutralKeyframe(double offset, PassRefPtr<TimingFunction> easing) const OVERRIDE FINAL;
+ virtual PassRefPtrWillBeRawPtr<Interpolation> createInterpolation(CSSPropertyID, WebCore::Keyframe::PropertySpecificKeyframe* end, Element*) const OVERRIDE FINAL;
+
+ virtual void trace(Visitor*) OVERRIDE;
+
+ private:
+ PropertySpecificKeyframe(double offset, PassRefPtr<TimingFunction> easing, PassRefPtrWillBeRawPtr<AnimatableValue>);
+
+ virtual PassOwnPtrWillBeRawPtr<Keyframe::PropertySpecificKeyframe> cloneWithOffset(double offset) const OVERRIDE;
+ virtual bool isAnimatableValuePropertySpecificKeyframe() const OVERRIDE { return true; }
+
+ RefPtrWillBeMember<AnimatableValue> m_value;
+ };
+
+private:
+ AnimatableValueKeyframe() { }
+
+ AnimatableValueKeyframe(const AnimatableValueKeyframe& copyFrom);
+
+ virtual PassRefPtrWillBeRawPtr<Keyframe> clone() const OVERRIDE;
+ virtual PassOwnPtrWillBeRawPtr<Keyframe::PropertySpecificKeyframe> createPropertySpecificKeyframe(CSSPropertyID) const OVERRIDE;
+
+ virtual bool isAnimatableValueKeyframe() const OVERRIDE { return true; }
+
+ typedef HashMap<CSSPropertyID, RefPtrWillBeMember<AnimatableValue> > PropertyValueMap;
+ PropertyValueMap m_propertyValues;
+};
+
+typedef AnimatableValueKeyframe::PropertySpecificKeyframe AnimatableValuePropertySpecificKeyframe;
+
+DEFINE_TYPE_CASTS(AnimatableValueKeyframe, Keyframe, value, value->isAnimatableValueKeyframe(), value.isAnimatableValueKeyframe());
+DEFINE_TYPE_CASTS(AnimatableValuePropertySpecificKeyframe, Keyframe::PropertySpecificKeyframe, value, value->isAnimatableValuePropertySpecificKeyframe(), value.isAnimatableValuePropertySpecificKeyframe());
+
+}
+
+#endif
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimatableValueTestHelper.cpp b/chromium/third_party/WebKit/Source/core/animation/AnimatableValueTestHelper.cpp
index da6958cfc21..f43065913a3 100644
--- a/chromium/third_party/WebKit/Source/core/animation/AnimatableValueTestHelper.cpp
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimatableValueTestHelper.cpp
@@ -32,8 +32,6 @@
#include "core/animation/AnimatableValueTestHelper.h"
-
-
namespace WebCore {
bool operator==(const AnimatableValue& a, const AnimatableValue& b)
@@ -53,50 +51,9 @@ void PrintTo(const AnimatableColor& animColor, ::std::ostream* os)
<< animColor.visitedLinkColor().serialized().utf8().data() << ")";
}
-void PrintTo(const AnimatableDouble& animDouble, ::std::ostream* os)
-{
- PrintTo(*(animDouble.toCSSValue().get()), os, "AnimatableDouble");
-}
-
void PrintTo(const AnimatableImage& animImage, ::std::ostream* os)
{
- PrintTo(*(animImage.toCSSValue().get()), os, "AnimatableImage");
-}
-
-void PrintTo(const AnimatableLength& animLength, ::std::ostream* os)
-{
- PrintTo(*(animLength.toCSSValue().get()), os, "AnimatableLength");
-}
-
-void PrintTo(const AnimatableLengthBox& animLengthBox, ::std::ostream* os)
-{
- *os << "AnimatableLengthBox(";
- PrintTo(*(animLengthBox.left()), os);
- *os << ", ";
- PrintTo(*(animLengthBox.right()), os);
- *os << ", ";
- PrintTo(*(animLengthBox.top()), os);
- *os << ", ";
- PrintTo(*(animLengthBox.bottom()), os);
- *os << ")";
-}
-
-void PrintTo(const AnimatableLengthPoint& animLengthPoint, ::std::ostream* os)
-{
- *os << "AnimatableLengthPoint(";
- PrintTo(*(animLengthPoint.x()), os);
- *os << ", ";
- PrintTo(*(animLengthPoint.y()), os);
- *os << ")";
-}
-
-void PrintTo(const AnimatableLengthSize& animLengthSize, ::std::ostream* os)
-{
- *os << "AnimatableLengthSize(";
- PrintTo(*(animLengthSize.width()), os);
- *os << ", ";
- PrintTo(*(animLengthSize.height()), os);
- *os << ")";
+ PrintTo(*(animImage.toCSSValue()), os, "AnimatableImage");
}
void PrintTo(const AnimatableNeutral& animValue, ::std::ostream* os)
@@ -108,8 +65,8 @@ void PrintTo(const AnimatableRepeatable& animValue, ::std::ostream* os)
{
*os << "AnimatableRepeatable(";
- const Vector<RefPtr<AnimatableValue> > v = animValue.values();
- for (Vector<RefPtr<AnimatableValue> >::const_iterator it = v.begin(); it != v.end(); ++it) {
+ const WillBeHeapVector<RefPtrWillBeMember<AnimatableValue> > v = animValue.values();
+ for (WillBeHeapVector<RefPtrWillBeMember<AnimatableValue> >::const_iterator it = v.begin(); it != v.end(); ++it) {
PrintTo(*(it->get()), os);
if (it+1 != v.end())
*os << ", ";
@@ -120,19 +77,7 @@ void PrintTo(const AnimatableRepeatable& animValue, ::std::ostream* os)
void PrintTo(const AnimatableSVGLength& animSVGLength, ::std::ostream* os)
{
*os << "AnimatableSVGLength("
- << animSVGLength.toSVGLength().valueAsString().utf8().data() << ")";
-}
-
-void PrintTo(const AnimatableSVGPaint& animSVGPaint, ::std::ostream* os)
-{
- *os << "AnimatableSVGPaint(";
- if (animSVGPaint.paintType() == SVGPaint::SVG_PAINTTYPE_RGBCOLOR)
- *os << animSVGPaint.color().serialized().utf8().data();
- else if (animSVGPaint.paintType() == SVGPaint::SVG_PAINTTYPE_URI)
- *os << "url(" << animSVGPaint.uri().utf8().data() << ")";
- else
- *os << animSVGPaint.paintType();
- *os << ")";
+ << animSVGLength.toSVGLength()->valueAsString().utf8().data() << ")";
}
void PrintTo(const AnimatableShapeValue& animValue, ::std::ostream* os)
@@ -143,10 +88,11 @@ void PrintTo(const AnimatableShapeValue& animValue, ::std::ostream* os)
void PrintTo(const AnimatableStrokeDasharrayList& animValue, ::std::ostream* os)
{
*os << "AnimatableStrokeDasharrayList(";
- const Vector<SVGLength> v = animValue.toSVGLengthVector();
- for (Vector<SVGLength>::const_iterator it = v.begin(); it != v.end(); ++it) {
- *os << it->valueAsString().utf8().data();
- if (it+1 != v.end())
+ RefPtr<SVGLengthList> list = animValue.toSVGLengthList();
+ size_t length = list->length();
+ for (size_t i = 0; i < length; ++i) {
+ *os << list->at(i)->valueAsString().utf8().data();
+ if (i != length-1)
*os << ", ";
}
*os << ")";
@@ -232,18 +178,8 @@ void PrintTo(const AnimatableValue& animValue, ::std::ostream* os)
PrintTo(*(toAnimatableClipPathOperation(&animValue)), os);
else if (animValue.isColor())
PrintTo(*(toAnimatableColor(&animValue)), os);
- else if (animValue.isDouble())
- PrintTo(*(toAnimatableDouble(&animValue)), os);
else if (animValue.isImage())
PrintTo(*(toAnimatableImage(&animValue)), os);
- else if (animValue.isLength())
- PrintTo(*(toAnimatableLength(&animValue)), os);
- else if (animValue.isLengthBox())
- PrintTo(*(toAnimatableLengthBox(&animValue)), os);
- else if (animValue.isLengthPoint())
- PrintTo(*(toAnimatableLengthPoint(&animValue)), os);
- else if (animValue.isLengthSize())
- PrintTo(*(toAnimatableLengthSize(&animValue)), os);
else if (animValue.isNeutral())
PrintTo(*(static_cast<const AnimatableNeutral*>(&animValue)), os);
else if (animValue.isRepeatable())
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimatableValueTestHelper.h b/chromium/third_party/WebKit/Source/core/animation/AnimatableValueTestHelper.h
index 65a86606768..ceed1bd85a7 100644
--- a/chromium/third_party/WebKit/Source/core/animation/AnimatableValueTestHelper.h
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimatableValueTestHelper.h
@@ -38,12 +38,7 @@
#include "core/animation/AnimatableClipPathOperation.h"
#include "core/animation/AnimatableColor.h"
-#include "core/animation/AnimatableDouble.h"
#include "core/animation/AnimatableImage.h"
-#include "core/animation/AnimatableLength.h"
-#include "core/animation/AnimatableLengthBox.h"
-#include "core/animation/AnimatableLengthPoint.h"
-#include "core/animation/AnimatableLengthSize.h"
#include "core/animation/AnimatableNeutral.h"
#include "core/animation/AnimatableRepeatable.h"
#include "core/animation/AnimatableSVGLength.h"
@@ -68,16 +63,10 @@ bool operator==(const AnimatableValue&, const AnimatableValue&);
void PrintTo(const AnimatableClipPathOperation&, ::std::ostream*);
void PrintTo(const AnimatableColor&, ::std::ostream*);
-void PrintTo(const AnimatableDouble&, ::std::ostream*);
void PrintTo(const AnimatableImage&, ::std::ostream*);
-void PrintTo(const AnimatableLength&, ::std::ostream*);
-void PrintTo(const AnimatableLengthBox&, ::std::ostream*);
-void PrintTo(const AnimatableLengthPoint&, ::std::ostream*);
-void PrintTo(const AnimatableLengthSize&, ::std::ostream*);
void PrintTo(const AnimatableNeutral&, ::std::ostream*);
void PrintTo(const AnimatableRepeatable&, ::std::ostream*);
void PrintTo(const AnimatableSVGLength&, ::std::ostream*);
-void PrintTo(const AnimatableSVGPaint&, ::std::ostream*);
void PrintTo(const AnimatableShapeValue&, ::std::ostream*);
void PrintTo(const AnimatableStrokeDasharrayList&, ::std::ostream*);
void PrintTo(const AnimatableTransform&, ::std::ostream*);
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimatableValueTestHelperTest.cpp b/chromium/third_party/WebKit/Source/core/animation/AnimatableValueTestHelperTest.cpp
index fad1a5a55e4..16bffd4eacc 100644
--- a/chromium/third_party/WebKit/Source/core/animation/AnimatableValueTestHelperTest.cpp
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimatableValueTestHelperTest.cpp
@@ -50,14 +50,9 @@ namespace {
class AnimationAnimatableValueTestHelperTest : public ::testing::Test {
protected:
- ::std::string PrintToString(PassRefPtr<AnimatableValue> animValue)
+ ::std::string PrintToString(PassRefPtrWillBeRawPtr<AnimatableValue> animValue)
{
- return PrintToString(animValue.get());
- }
-
- ::std::string PrintToString(const AnimatableValue* animValue)
- {
- return ::testing::PrintToString(*animValue);
+ return ::testing::PrintToString(*animValue.get());
}
};
@@ -72,70 +67,29 @@ TEST_F(AnimationAnimatableValueTestHelperTest, PrintTo)
::std::string("AnimatableColor(rgba(0, 0, 0, 0), #ff0000)"),
PrintToString(AnimatableColor::create(Color(0x000000FF), Color(0xFFFF0000))));
- EXPECT_EQ(
- ::std::string("AnimatableDouble(1)"),
- PrintToString(AnimatableDouble::create(1.0)));
-
- EXPECT_EQ(
- ::std::string("AnimatableLength(5px)"),
- PrintToString(AnimatableLength::create(CSSPrimitiveValue::create(5, CSSPrimitiveValue::CSS_PX).get())));
-
- EXPECT_EQ(
- ::std::string("AnimatableLengthBox(AnimatableLength(1px), AnimatableLength(2em), AnimatableLength(3rem), AnimatableLength(4pt))"),
- PrintToString(AnimatableLengthBox::create(
- AnimatableLength::create(CSSPrimitiveValue::create(1, CSSPrimitiveValue::CSS_PX).get()),
- AnimatableLength::create(CSSPrimitiveValue::create(2, CSSPrimitiveValue::CSS_EMS).get()),
- AnimatableLength::create(CSSPrimitiveValue::create(3, CSSPrimitiveValue::CSS_REMS).get()),
- AnimatableLength::create(CSSPrimitiveValue::create(4, CSSPrimitiveValue::CSS_PT).get())
- )));
-
- EXPECT_EQ(
- ::std::string("AnimatableLengthPoint(AnimatableLength(5%), AnimatableLength(6px))"),
- PrintToString(AnimatableLengthPoint::create(
- AnimatableLength::create(CSSPrimitiveValue::create(5, CSSPrimitiveValue::CSS_PERCENTAGE).get()),
- AnimatableLength::create(CSSPrimitiveValue::create(6, CSSPrimitiveValue::CSS_PX).get())
- )));
-
- EXPECT_EQ(
- ::std::string("AnimatableLengthSize(AnimatableLength(3rem), AnimatableLength(4pt))"),
- PrintToString(AnimatableLengthSize::create(
- AnimatableLength::create(CSSPrimitiveValue::create(3, CSSPrimitiveValue::CSS_REMS).get()),
- AnimatableLength::create(CSSPrimitiveValue::create(4, CSSPrimitiveValue::CSS_PT).get())
- )));
-
EXPECT_THAT(
- PrintToString(AnimatableValue::neutralValue()),
+ PrintToString(const_cast<AnimatableValue*>(AnimatableValue::neutralValue())),
testing::StartsWith("AnimatableNeutral@"));
- Vector<RefPtr<AnimatableValue> > v1;
- v1.append(AnimatableLength::create(CSSPrimitiveValue::create(3, CSSPrimitiveValue::CSS_REMS).get()));
- v1.append(AnimatableLength::create(CSSPrimitiveValue::create(4, CSSPrimitiveValue::CSS_PT).get()));
- EXPECT_EQ(
- ::std::string("AnimatableRepeatable(AnimatableLength(3rem), AnimatableLength(4pt))"),
- PrintToString(AnimatableRepeatable::create(v1)));
+ RefPtr<SVGLength> length1cm = SVGLength::create(LengthModeOther);
+ RefPtr<SVGLength> length2cm = SVGLength::create(LengthModeOther);
+ length1cm->setValueAsString("1cm", ASSERT_NO_EXCEPTION);
+ length2cm->setValueAsString("2cm", ASSERT_NO_EXCEPTION);
EXPECT_EQ(
::std::string("AnimatableSVGLength(1cm)"),
- PrintToString(AnimatableSVGLength::create(SVGLength(LengthModeOther, "1cm"))));
-
- EXPECT_EQ(
- ::std::string("AnimatableSVGPaint(#ff0000)"),
- PrintToString(AnimatableSVGPaint::create(SVGPaint::SVG_PAINTTYPE_RGBCOLOR, Color(0xFFFF0000), "")));
-
- EXPECT_EQ(
- ::std::string("AnimatableSVGPaint(url(abc))"),
- PrintToString(AnimatableSVGPaint::create(SVGPaint::SVG_PAINTTYPE_URI, Color(0xFFFF0000), "abc")));
+ PrintToString(AnimatableSVGLength::create(length1cm)));
EXPECT_THAT(
- PrintToString(AnimatableShapeValue::create(ShapeValue::createShapeValue(BasicShapeCircle::create().get()).get())),
+ PrintToString(AnimatableShapeValue::create(ShapeValue::createShapeValue(BasicShapeCircle::create().get(), ContentBox).get())),
testing::StartsWith("AnimatableShapeValue@"));
- Vector<SVGLength> v2;
- v2.append(SVGLength(LengthModeOther, "1cm"));
- v2.append(SVGLength(LengthModeOther, "2cm"));
+ RefPtr<SVGLengthList> l2 = SVGLengthList::create();
+ l2->append(length1cm);
+ l2->append(length2cm);
EXPECT_EQ(
::std::string("AnimatableStrokeDasharrayList(1cm, 2cm)"),
- PrintToString(AnimatableStrokeDasharrayList::create(v2)));
+ PrintToString(AnimatableStrokeDasharrayList::create(l2)));
TransformOperations operations1;
operations1.operations().append(TranslateTransformOperation::create(Length(2, WebCore::Fixed), Length(0, WebCore::Fixed), TransformOperation::TranslateX));
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimatableVisibility.cpp b/chromium/third_party/WebKit/Source/core/animation/AnimatableVisibility.cpp
index a395efa2b2c..573783f9e1b 100644
--- a/chromium/third_party/WebKit/Source/core/animation/AnimatableVisibility.cpp
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimatableVisibility.cpp
@@ -33,7 +33,14 @@
namespace WebCore {
-PassRefPtr<AnimatableValue> AnimatableVisibility::interpolateTo(const AnimatableValue* value, double fraction) const
+bool AnimatableVisibility::usesDefaultInterpolationWith(const AnimatableValue* value) const
+{
+ EVisibility from = m_visibility;
+ EVisibility to = toAnimatableVisibility(value)->m_visibility;
+ return from != VISIBLE && to != VISIBLE;
+}
+
+PassRefPtrWillBeRawPtr<AnimatableValue> AnimatableVisibility::interpolateTo(const AnimatableValue* value, double fraction) const
{
EVisibility from = m_visibility;
EVisibility to = toAnimatableVisibility(value)->m_visibility;
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimatableVisibility.h b/chromium/third_party/WebKit/Source/core/animation/AnimatableVisibility.h
index bbd377105d0..72d653ebc66 100644
--- a/chromium/third_party/WebKit/Source/core/animation/AnimatableVisibility.h
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimatableVisibility.h
@@ -36,18 +36,21 @@
namespace WebCore {
-class AnimatableVisibility : public AnimatableValue {
+class AnimatableVisibility FINAL : public AnimatableValue {
public:
virtual ~AnimatableVisibility() { }
- static PassRefPtr<AnimatableVisibility> create(EVisibility visibility)
+ static PassRefPtrWillBeRawPtr<AnimatableVisibility> create(EVisibility visibility)
{
- return adoptRef(new AnimatableVisibility(visibility));
+ return adoptRefWillBeNoop(new AnimatableVisibility(visibility));
}
EVisibility visibility() const { return m_visibility; }
+ virtual void trace(Visitor* visitor) OVERRIDE { AnimatableValue::trace(visitor); }
+
protected:
- virtual PassRefPtr<AnimatableValue> interpolateTo(const AnimatableValue*, double fraction) const OVERRIDE;
+ virtual PassRefPtrWillBeRawPtr<AnimatableValue> interpolateTo(const AnimatableValue*, double fraction) const OVERRIDE;
+ virtual bool usesDefaultInterpolationWith(const AnimatableValue*) const OVERRIDE;
private:
explicit AnimatableVisibility(EVisibility visibility)
diff --git a/chromium/third_party/WebKit/Source/core/animation/Animation.cpp b/chromium/third_party/WebKit/Source/core/animation/Animation.cpp
index 6e40086d6f2..4eedf009903 100644
--- a/chromium/third_party/WebKit/Source/core/animation/Animation.cpp
+++ b/chromium/third_party/WebKit/Source/core/animation/Animation.cpp
@@ -31,136 +31,236 @@
#include "config.h"
#include "core/animation/Animation.h"
+#include "bindings/v8/Dictionary.h"
+#include "bindings/v8/ExceptionState.h"
#include "core/animation/ActiveAnimations.h"
+#include "core/animation/AnimationHelpers.h"
+#include "core/animation/AnimationPlayer.h"
+#include "core/animation/AnimationTimeline.h"
#include "core/animation/CompositorAnimations.h"
-#include "core/animation/KeyframeAnimationEffect.h"
-#include "core/animation/Player.h"
+#include "core/animation/KeyframeEffectModel.h"
+#include "core/animation/interpolation/Interpolation.h"
#include "core/dom/Element.h"
+#include "core/frame/UseCounter.h"
+#include "core/rendering/RenderLayer.h"
namespace WebCore {
-PassRefPtr<Animation> Animation::create(PassRefPtr<Element> target, PassRefPtr<AnimationEffect> effect, const Timing& timing, Priority priority, PassOwnPtr<EventDelegate> eventDelegate)
+PassRefPtrWillBeRawPtr<Animation> Animation::create(Element* target, PassRefPtrWillBeRawPtr<AnimationEffect> effect, const Timing& timing, Priority priority, PassOwnPtr<EventDelegate> eventDelegate)
{
- return adoptRef(new Animation(target, effect, timing, priority, eventDelegate));
+ return adoptRefWillBeNoop(new Animation(target, effect, timing, priority, eventDelegate));
}
-Animation::Animation(PassRefPtr<Element> target, PassRefPtr<AnimationEffect> effect, const Timing& timing, Priority priority, PassOwnPtr<EventDelegate> eventDelegate)
- : TimedItem(timing, eventDelegate)
+PassRefPtrWillBeRawPtr<Animation> Animation::create(Element* element, PassRefPtrWillBeRawPtr<AnimationEffect> effect, const Dictionary& timingInputDictionary)
+{
+ ASSERT(RuntimeEnabledFeatures::webAnimationsAPIEnabled());
+ return create(element, effect, TimingInput::convert(timingInputDictionary));
+}
+PassRefPtrWillBeRawPtr<Animation> Animation::create(Element* element, PassRefPtrWillBeRawPtr<AnimationEffect> effect, double duration)
+{
+ ASSERT(RuntimeEnabledFeatures::webAnimationsAPIEnabled());
+ return create(element, effect, TimingInput::convert(duration));
+}
+PassRefPtrWillBeRawPtr<Animation> Animation::create(Element* element, PassRefPtrWillBeRawPtr<AnimationEffect> effect)
+{
+ ASSERT(RuntimeEnabledFeatures::webAnimationsAPIEnabled());
+ return create(element, effect, Timing());
+}
+PassRefPtrWillBeRawPtr<Animation> Animation::create(Element* element, const Vector<Dictionary>& keyframeDictionaryVector, const Dictionary& timingInputDictionary, ExceptionState& exceptionState)
+{
+ ASSERT(RuntimeEnabledFeatures::webAnimationsAPIEnabled());
+ if (element)
+ UseCounter::count(element->document(), UseCounter::AnimationConstructorKeyframeListEffectObjectTiming);
+ return create(element, EffectInput::convert(element, keyframeDictionaryVector, exceptionState), TimingInput::convert(timingInputDictionary));
+}
+PassRefPtrWillBeRawPtr<Animation> Animation::create(Element* element, const Vector<Dictionary>& keyframeDictionaryVector, double duration, ExceptionState& exceptionState)
+{
+ ASSERT(RuntimeEnabledFeatures::webAnimationsAPIEnabled());
+ if (element)
+ UseCounter::count(element->document(), UseCounter::AnimationConstructorKeyframeListEffectDoubleTiming);
+ return create(element, EffectInput::convert(element, keyframeDictionaryVector, exceptionState), TimingInput::convert(duration));
+}
+PassRefPtrWillBeRawPtr<Animation> Animation::create(Element* element, const Vector<Dictionary>& keyframeDictionaryVector, ExceptionState& exceptionState)
+{
+ ASSERT(RuntimeEnabledFeatures::webAnimationsAPIEnabled());
+ if (element)
+ UseCounter::count(element->document(), UseCounter::AnimationConstructorKeyframeListEffectNoTiming);
+ return create(element, EffectInput::convert(element, keyframeDictionaryVector, exceptionState), Timing());
+}
+
+Animation::Animation(Element* target, PassRefPtrWillBeRawPtr<AnimationEffect> effect, const Timing& timing, Priority priority, PassOwnPtr<EventDelegate> eventDelegate)
+ : AnimationNode(timing, eventDelegate)
, m_target(target)
, m_effect(effect)
- , m_activeInAnimationStack(false)
+ , m_sampledEffect(nullptr)
, m_priority(priority)
{
+#if !ENABLE(OILPAN)
+ if (m_target)
+ m_target->ensureActiveAnimations().addAnimation(this);
+#endif
}
-void Animation::didAttach()
+Animation::~Animation()
{
+#if !ENABLE(OILPAN)
if (m_target)
- m_target->ensureActiveAnimations()->players().add(player());
+ m_target->activeAnimations()->notifyAnimationDestroyed(this);
+#endif
}
-void Animation::willDetach()
+void Animation::attach(AnimationPlayer* player)
+{
+ if (m_target) {
+ m_target->ensureActiveAnimations().addPlayer(player);
+ m_target->setNeedsAnimationStyleRecalc();
+ }
+ AnimationNode::attach(player);
+}
+
+void Animation::detach()
{
if (m_target)
- m_target->activeAnimations()->players().remove(player());
- if (m_activeInAnimationStack)
+ m_target->activeAnimations()->removePlayer(player());
+ if (m_sampledEffect)
clearEffects();
+ AnimationNode::detach();
+}
+
+void Animation::specifiedTimingChanged()
+{
+ cancelAnimationOnCompositor();
+ if (player()) {
+ // FIXME: Needs to consider groups when added.
+ ASSERT(player()->source() == this);
+ player()->schedulePendingAnimationOnCompositor();
+ }
}
static AnimationStack& ensureAnimationStack(Element* element)
{
- return element->ensureActiveAnimations()->defaultStack();
+ return element->ensureActiveAnimations().defaultStack();
}
-bool Animation::applyEffects(bool previouslyInEffect)
+void Animation::applyEffects()
{
ASSERT(isInEffect());
+ ASSERT(player());
if (!m_target || !m_effect)
- return false;
-
- if (player() && !previouslyInEffect) {
- ensureAnimationStack(m_target.get()).add(this);
- m_activeInAnimationStack = true;
- }
+ return;
double iteration = currentIteration();
ASSERT(iteration >= 0);
// FIXME: Handle iteration values which overflow int.
- m_compositableValues = m_effect->sample(static_cast<int>(iteration), timeFraction());
- if (player()) {
- m_target->setNeedsAnimationStyleRecalc();
- return true;
+ OwnPtrWillBeRawPtr<WillBeHeapVector<RefPtrWillBeMember<Interpolation> > > interpolations = m_effect->sample(static_cast<int>(iteration), timeFraction(), iterationDuration());
+ if (m_sampledEffect) {
+ m_sampledEffect->setInterpolations(interpolations.release());
+ } else if (!interpolations->isEmpty()) {
+ OwnPtrWillBeRawPtr<SampledEffect> sampledEffect = SampledEffect::create(this, interpolations.release());
+ m_sampledEffect = sampledEffect.get();
+ ensureAnimationStack(m_target).add(sampledEffect.release());
+ } else {
+ return;
}
- return false;
+
+ m_target->setNeedsAnimationStyleRecalc();
}
void Animation::clearEffects()
{
ASSERT(player());
- ASSERT(m_activeInAnimationStack);
- ensureAnimationStack(m_target.get()).remove(this);
+ ASSERT(m_sampledEffect);
+
+ m_sampledEffect->clear();
+ m_sampledEffect = nullptr;
cancelAnimationOnCompositor();
- m_activeInAnimationStack = false;
- m_compositableValues.clear();
m_target->setNeedsAnimationStyleRecalc();
invalidate();
}
-bool Animation::updateChildrenAndEffects() const
+void Animation::updateChildrenAndEffects() const
{
if (!m_effect)
- return false;
-
+ return;
if (isInEffect())
- return const_cast<Animation*>(this)->applyEffects(m_activeInAnimationStack);
-
- if (m_activeInAnimationStack) {
+ const_cast<Animation*>(this)->applyEffects();
+ else if (m_sampledEffect)
const_cast<Animation*>(this)->clearEffects();
- return true;
- }
- return false;
}
-double Animation::calculateTimeToEffectChange(double localTime, double timeToNextIteration) const
+double Animation::calculateTimeToEffectChange(bool forwards, double localTime, double timeToNextIteration) const
{
- const double activeStartTime = startTime() + specified().startDelay;
+ const double start = startTimeInternal() + specifiedTiming().startDelay;
+ const double end = start + activeDurationInternal();
+
switch (phase()) {
case PhaseBefore:
- return activeStartTime - localTime;
+ ASSERT(start >= localTime);
+ return forwards
+ ? start - localTime
+ : std::numeric_limits<double>::infinity();
case PhaseActive:
- if (hasActiveAnimationsOnCompositor()) {
+ if (forwards && hasActiveAnimationsOnCompositor()) {
+ ASSERT(specifiedTiming().playbackRate == 1);
// Need service to apply fill / fire events.
- const double activeEndTime = activeStartTime + activeDuration();
- return std::min(activeEndTime - localTime, timeToNextIteration);
+ const double timeToEnd = end - localTime;
+ if (hasEvents()) {
+ return std::min(timeToEnd, timeToNextIteration);
+ } else {
+ return timeToEnd;
+ }
}
return 0;
case PhaseAfter:
+ ASSERT(localTime >= end);
// If this Animation 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 std::numeric_limits<double>::infinity();
- case PhaseNone:
+ return forwards
+ ? std::numeric_limits<double>::infinity()
+ : localTime - end;
default:
ASSERT_NOT_REACHED();
- return 0;
+ return std::numeric_limits<double>::infinity();
}
}
+void Animation::notifySampledEffectRemovedFromAnimationStack()
+{
+ ASSERT(m_sampledEffect);
+ m_sampledEffect = nullptr;
+}
+
+#if !ENABLE(OILPAN)
+void Animation::notifyElementDestroyed()
+{
+ // If our player is kept alive just by the sampledEffect, we might get our
+ // destructor called when we call SampledEffect::clear(), so we need to
+ // clear m_sampledEffect first.
+ m_target = nullptr;
+ clearEventDelegate();
+ SampledEffect* sampledEffect = m_sampledEffect;
+ m_sampledEffect = nullptr;
+ if (sampledEffect)
+ sampledEffect->clear();
+}
+#endif
+
bool Animation::isCandidateForAnimationOnCompositor() const
{
if (!effect() || !m_target)
return false;
- return CompositorAnimations::instance()->isCandidateForAnimationOnCompositor(specified(), *effect());
+ return CompositorAnimations::instance()->isCandidateForAnimationOnCompositor(specifiedTiming(), *effect());
}
-bool Animation::maybeStartAnimationOnCompositor()
+bool Animation::maybeStartAnimationOnCompositor(double startTime)
{
ASSERT(!hasActiveAnimationsOnCompositor());
if (!isCandidateForAnimationOnCompositor())
return false;
- if (!CompositorAnimations::instance()->canStartAnimationOnCompositor(*m_target.get()))
+ if (!CompositorAnimations::instance()->canStartAnimationOnCompositor(*m_target))
return false;
- if (!CompositorAnimations::instance()->startAnimationOnCompositor(*m_target.get(), specified(), *effect(), m_compositorAnimationIds))
+ if (!CompositorAnimations::instance()->startAnimationOnCompositor(*m_target, startTime, specifiedTiming(), *effect(), m_compositorAnimationIds))
return false;
ASSERT(!m_compositorAnimationIds.isEmpty());
return true;
@@ -183,12 +283,16 @@ bool Animation::affects(CSSPropertyID property) const
void Animation::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;
if (!m_target || !m_target->renderer())
return;
for (size_t i = 0; i < m_compositorAnimationIds.size(); ++i)
- CompositorAnimations::instance()->cancelAnimationOnCompositor(*m_target.get(), m_compositorAnimationIds[i]);
+ CompositorAnimations::instance()->cancelAnimationOnCompositor(*m_target, m_compositorAnimationIds[i]);
m_compositorAnimationIds.clear();
}
@@ -198,7 +302,15 @@ void Animation::pauseAnimationForTestingOnCompositor(double pauseTime)
if (!m_target || !m_target->renderer())
return;
for (size_t i = 0; i < m_compositorAnimationIds.size(); ++i)
- CompositorAnimations::instance()->pauseAnimationForTestingOnCompositor(*m_target.get(), m_compositorAnimationIds[i], pauseTime);
+ CompositorAnimations::instance()->pauseAnimationForTestingOnCompositor(*m_target, m_compositorAnimationIds[i], pauseTime);
+}
+
+void Animation::trace(Visitor* visitor)
+{
+ visitor->trace(m_target);
+ visitor->trace(m_effect);
+ visitor->trace(m_sampledEffect);
+ AnimationNode::trace(visitor);
}
} // namespace WebCore
diff --git a/chromium/third_party/WebKit/Source/core/animation/Animation.h b/chromium/third_party/WebKit/Source/core/animation/Animation.h
index f4ad206d503..f0340516108 100644
--- a/chromium/third_party/WebKit/Source/core/animation/Animation.h
+++ b/chromium/third_party/WebKit/Source/core/animation/Animation.h
@@ -32,66 +32,81 @@
#define Animation_h
#include "core/animation/AnimationEffect.h"
-#include "core/animation/TimedItem.h"
+#include "core/animation/AnimationNode.h"
+#include "core/animation/EffectInput.h"
+#include "core/animation/TimingInput.h"
+#include "platform/heap/Handle.h"
#include "wtf/RefPtr.h"
namespace WebCore {
+class Dictionary;
class Element;
+class ExceptionState;
+class SampledEffect;
-class Animation FINAL : public TimedItem {
-
+class Animation FINAL : public AnimationNode {
public:
enum Priority { DefaultPriority, TransitionPriority };
- static PassRefPtr<Animation> create(PassRefPtr<Element>, PassRefPtr<AnimationEffect>, const Timing&, Priority = DefaultPriority, PassOwnPtr<EventDelegate> = nullptr);
- virtual bool isAnimation() const OVERRIDE FINAL { return true; }
+ static PassRefPtrWillBeRawPtr<Animation> create(Element*, PassRefPtrWillBeRawPtr<AnimationEffect>, const Timing&, Priority = DefaultPriority, PassOwnPtr<EventDelegate> = nullptr);
+ // Web Animations API Bindings constructors.
+ static PassRefPtrWillBeRawPtr<Animation> create(Element*, PassRefPtrWillBeRawPtr<AnimationEffect>, const Dictionary& timingInputDictionary);
+ static PassRefPtrWillBeRawPtr<Animation> create(Element*, PassRefPtrWillBeRawPtr<AnimationEffect>, double duration);
+ static PassRefPtrWillBeRawPtr<Animation> create(Element*, PassRefPtrWillBeRawPtr<AnimationEffect>);
+ static PassRefPtrWillBeRawPtr<Animation> create(Element*, const Vector<Dictionary>& keyframeDictionaryVector, const Dictionary& timingInputDictionary, ExceptionState&);
+ static PassRefPtrWillBeRawPtr<Animation> create(Element*, const Vector<Dictionary>& keyframeDictionaryVector, double duration, ExceptionState&);
+ static PassRefPtrWillBeRawPtr<Animation> create(Element*, const Vector<Dictionary>& keyframeDictionaryVector, ExceptionState&);
+
+ virtual ~Animation();
- const AnimationEffect::CompositableValueList* compositableValues() const
- {
- ASSERT(m_compositableValues);
- return m_compositableValues.get();
- }
+ virtual bool isAnimation() const OVERRIDE { return true; }
bool affects(CSSPropertyID) const;
const AnimationEffect* effect() const { return m_effect.get(); }
+ AnimationEffect* effect() { return m_effect.get(); }
Priority priority() const { return m_priority; }
- Element* target() { return m_target.get(); }
+ Element* target() { return m_target; }
+
+ void notifySampledEffectRemovedFromAnimationStack();
+#if !ENABLE(OILPAN)
+ void notifyElementDestroyed();
+#endif
bool isCandidateForAnimationOnCompositor() const;
- // Must only be called once and assumes to be part of a player without a start time.
- bool maybeStartAnimationOnCompositor();
+ // Must only be called once.
+ bool maybeStartAnimationOnCompositor(double startTime);
bool hasActiveAnimationsOnCompositor() const;
bool hasActiveAnimationsOnCompositor(CSSPropertyID) const;
void cancelAnimationOnCompositor();
void pauseAnimationForTestingOnCompositor(double pauseTime);
+ virtual void trace(Visitor*);
+
protected:
- // Returns whether style recalc was triggered.
- virtual bool applyEffects(bool previouslyInEffect);
- virtual void clearEffects();
- virtual bool updateChildrenAndEffects() const OVERRIDE FINAL;
- virtual void didAttach() OVERRIDE FINAL;
- virtual void willDetach() OVERRIDE FINAL;
- virtual double calculateTimeToEffectChange(double inheritedTime, double timeToNextIteration) const OVERRIDE FINAL;
+ void applyEffects();
+ void clearEffects();
+ virtual void updateChildrenAndEffects() const OVERRIDE;
+ virtual void attach(AnimationPlayer*) OVERRIDE;
+ virtual void detach() OVERRIDE;
+ virtual void specifiedTimingChanged() OVERRIDE;
+ virtual double calculateTimeToEffectChange(bool forwards, double inheritedTime, double timeToNextIteration) const OVERRIDE;
private:
- Animation(PassRefPtr<Element>, PassRefPtr<AnimationEffect>, const Timing&, Priority, PassOwnPtr<EventDelegate>);
-
- RefPtr<Element> m_target;
- RefPtr<AnimationEffect> m_effect;
+ Animation(Element*, PassRefPtrWillBeRawPtr<AnimationEffect>, const Timing&, Priority, PassOwnPtr<EventDelegate>);
- bool m_activeInAnimationStack;
- OwnPtr<AnimationEffect::CompositableValueList> m_compositableValues;
+ RawPtrWillBeMember<Element> m_target;
+ RefPtrWillBeMember<AnimationEffect> m_effect;
+ RawPtrWillBeMember<SampledEffect> m_sampledEffect;
Priority m_priority;
Vector<int> m_compositorAnimationIds;
- friend class CSSAnimations;
+ friend class AnimationAnimationV8Test;
};
-DEFINE_TYPE_CASTS(Animation, TimedItem, timedItem, timedItem->isAnimation(), timedItem.isAnimation());
+DEFINE_TYPE_CASTS(Animation, AnimationNode, animationNode, animationNode->isAnimation(), animationNode.isAnimation());
} // namespace WebCore
diff --git a/chromium/third_party/WebKit/Source/core/animation/css/TransitionTimeline.h b/chromium/third_party/WebKit/Source/core/animation/Animation.idl
index 6d55f48772e..02b98bf8234 100644
--- a/chromium/third_party/WebKit/Source/core/animation/css/TransitionTimeline.h
+++ b/chromium/third_party/WebKit/Source/core/animation/Animation.idl
@@ -28,21 +28,14 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef TransitionTimeline_h
-#define TransitionTimeline_h
+// http://dev.w3.org/fxtf/web-animations/#idl-def-Animation
-#include "core/animation/DocumentTimeline.h"
-
-namespace WebCore {
-
-class TransitionTimeline FINAL : public DocumentTimeline {
-public:
- static PassRefPtr<TransitionTimeline> create(Document*, PassOwnPtr<PlatformTiming> = nullptr);
-
-private:
- TransitionTimeline(Document*, PassOwnPtr<PlatformTiming>);
+[
+ // FIXME: should be optional union type http://crbug.com/240176
+ Constructor(Element? target, sequence<Dictionary> keyframes),
+ Constructor(Element? target, sequence<Dictionary> keyframes, double timingInput),
+ Constructor(Element? target, sequence<Dictionary> keyframes, Dictionary timingInput),
+ RaisesException=Constructor,
+ RuntimeEnabled=WebAnimationsAPI,
+] interface Animation : AnimationNode {
};
-
-} // namespace WebCore
-
-#endif
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimationClock.cpp b/chromium/third_party/WebKit/Source/core/animation/AnimationClock.cpp
new file mode 100644
index 00000000000..d51c95e7aed
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimationClock.cpp
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2014, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "core/animation/AnimationClock.h"
+
+#include "wtf/CurrentTime.h"
+#include <math.h>
+
+namespace {
+
+// FIXME: This is an approximation of time between frames, used when
+// ticking the animation clock outside of animation frame callbacks.
+// Ideally this would be generated by the compositor.
+const double approximateFrameTime = 1 / 60.0;
+
+}
+
+namespace WebCore {
+
+unsigned AnimationClock::s_currentTask = 0;
+
+void AnimationClock::updateTime(double time)
+{
+ if (time > m_time)
+ m_time = time;
+ m_currentTask = s_currentTask;
+}
+
+double AnimationClock::currentTime()
+{
+ if (m_currentTask != s_currentTask) {
+ const double currentTime = m_monotonicallyIncreasingTime();
+ if (m_time < currentTime) {
+ // Advance to the first estimated frame after the current time.
+ const double frameShift = fmod(currentTime - m_time, approximateFrameTime);
+ const double newTime = currentTime + (approximateFrameTime - frameShift);
+ ASSERT(newTime >= currentTime);
+ ASSERT(newTime <= currentTime + approximateFrameTime);
+ updateTime(newTime);
+ } else {
+ m_currentTask = s_currentTask;
+ }
+ }
+ return m_time;
+}
+
+void AnimationClock::resetTimeForTesting()
+{
+ m_time = 0;
+ m_currentTask = 0;
+ s_currentTask = 0;
+}
+
+}
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimationClock.h b/chromium/third_party/WebKit/Source/core/animation/AnimationClock.h
index f6a2cdb8499..b5bb0d9adc6 100644
--- a/chromium/third_party/WebKit/Source/core/animation/AnimationClock.h
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimationClock.h
@@ -32,45 +32,33 @@
#define AnimationClock_h
#include "wtf/CurrentTime.h"
+#include "wtf/Noncopyable.h"
#include "wtf/PassOwnPtr.h"
+#include <limits>
namespace WebCore {
class AnimationClock {
+ WTF_MAKE_NONCOPYABLE(AnimationClock);
public:
- static PassOwnPtr<AnimationClock> create(WTF::TimeFunction monotonicallyIncreasingTime = WTF::monotonicallyIncreasingTime)
- {
- return adoptPtr(new AnimationClock(monotonicallyIncreasingTime));
- }
-
- void updateTime(double time)
- {
- if (time > m_time)
- m_time = time;
- m_frozen = true;
- }
-
- double currentTime()
+ explicit AnimationClock(WTF::TimeFunction monotonicallyIncreasingTime = WTF::monotonicallyIncreasingTime)
+ : m_monotonicallyIncreasingTime(monotonicallyIncreasingTime)
+ , m_time(0)
+ , m_currentTask(std::numeric_limits<unsigned>::max())
{
- if (!m_frozen)
- updateTime(m_monotonicallyIncreasingTime());
- return m_time;
}
- void unfreeze() { m_frozen = false; }
+ void updateTime(double time);
+ double currentTime();
+ void resetTimeForTesting();
- void resetTimeForTesting() { m_time = 0; m_frozen = true; }
+ static void notifyTaskStart() { ++s_currentTask; }
private:
- AnimationClock(WTF::TimeFunction monotonicallyIncreasingTime)
- : m_monotonicallyIncreasingTime(monotonicallyIncreasingTime)
- , m_time(0)
- , m_frozen(false)
- {
- }
WTF::TimeFunction m_monotonicallyIncreasingTime;
double m_time;
- bool m_frozen;
+ unsigned m_currentTask;
+ static unsigned s_currentTask;
};
} // namespace WebCore
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimationClockTest.cpp b/chromium/third_party/WebKit/Source/core/animation/AnimationClockTest.cpp
index 248da7badee..89412585331 100644
--- a/chromium/third_party/WebKit/Source/core/animation/AnimationClockTest.cpp
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimationClockTest.cpp
@@ -39,41 +39,105 @@ using namespace WebCore;
namespace {
class AnimationAnimationClockTest : public ::testing::Test {
+public:
+ AnimationAnimationClockTest()
+ : animationClock(mockTimeFunction)
+ { }
protected:
virtual void SetUp()
{
- animationClock = AnimationClock::create(mockTimeFunction);
- mockTime = 200;
+ mockTime = 0;
+ animationClock.resetTimeForTesting();
}
static double mockTimeFunction()
{
- return mockTime++;
+ return mockTime;
}
static double mockTime;
- OwnPtr<AnimationClock> animationClock;
+ AnimationClock animationClock;
};
double AnimationAnimationClockTest::mockTime;
-TEST_F(AnimationAnimationClockTest, CurrentTime)
+TEST_F(AnimationAnimationClockTest, TimeIsGreaterThanZeroForUnitTests)
{
- EXPECT_EQ(200, animationClock->currentTime());
- EXPECT_EQ(200, animationClock->currentTime());
- animationClock->unfreeze();
- EXPECT_EQ(201, animationClock->currentTime());
- EXPECT_EQ(201, animationClock->currentTime());
+ AnimationClock clock;
+ // unit tests outside core/animation shouldn't need to do anything to get
+ // a non-zero currentTime().
+ EXPECT_GT(clock.currentTime(), 0);
}
-TEST_F(AnimationAnimationClockTest, UpdateTime)
+TEST_F(AnimationAnimationClockTest, TimeDoesNotChange)
{
- animationClock->updateTime(100);
- EXPECT_EQ(100, animationClock->currentTime());
- EXPECT_EQ(100, animationClock->currentTime());
- animationClock->updateTime(150);
- EXPECT_EQ(150, animationClock->currentTime());
- EXPECT_EQ(150, animationClock->currentTime());
+ animationClock.updateTime(100);
+ EXPECT_EQ(100, animationClock.currentTime());
+ EXPECT_EQ(100, animationClock.currentTime());
+}
+
+TEST_F(AnimationAnimationClockTest, TimeAdvancesWhenUpdated)
+{
+ animationClock.updateTime(100);
+ EXPECT_EQ(100, animationClock.currentTime());
+
+ animationClock.updateTime(200);
+ EXPECT_EQ(200, animationClock.currentTime());
+}
+
+TEST_F(AnimationAnimationClockTest, TimeAdvancesToTaskTime)
+{
+ animationClock.updateTime(100);
+ EXPECT_EQ(100, animationClock.currentTime());
+
+ mockTime = 150;
+ AnimationClock::notifyTaskStart();
+ EXPECT_GE(animationClock.currentTime(), mockTime);
+}
+
+TEST_F(AnimationAnimationClockTest, TimeAdvancesToTaskTimeOnlyWhenRequired)
+{
+ animationClock.updateTime(100);
+ EXPECT_EQ(100, animationClock.currentTime());
+
+ AnimationClock::notifyTaskStart();
+ animationClock.updateTime(125);
+ EXPECT_EQ(125, animationClock.currentTime());
+}
+
+TEST_F(AnimationAnimationClockTest, UpdateTimeIsMonotonic)
+{
+ animationClock.updateTime(100);
+ EXPECT_EQ(100, animationClock.currentTime());
+
+ // Update can't go backwards.
+ animationClock.updateTime(50);
+ EXPECT_EQ(100, animationClock.currentTime());
+
+ mockTime = 50;
+ AnimationClock::notifyTaskStart();
+ EXPECT_EQ(100, animationClock.currentTime());
+
+ mockTime = 150;
+ AnimationClock::notifyTaskStart();
+ EXPECT_GE(animationClock.currentTime(), mockTime);
+
+ // Update can't go backwards after advance to estimate.
+ animationClock.updateTime(100);
+ EXPECT_GE(animationClock.currentTime(), mockTime);
+}
+
+TEST_F(AnimationAnimationClockTest, CurrentTimeUpdatesTask)
+{
+ animationClock.updateTime(100);
+ EXPECT_EQ(100, animationClock.currentTime());
+
+ mockTime = 100;
+ AnimationClock::notifyTaskStart();
+ EXPECT_EQ(100, animationClock.currentTime());
+
+ mockTime = 150;
+ EXPECT_EQ(100, animationClock.currentTime());
}
}
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimationEffect.h b/chromium/third_party/WebKit/Source/core/animation/AnimationEffect.h
index d675a5f4a9e..a8772648cf1 100644
--- a/chromium/third_party/WebKit/Source/core/animation/AnimationEffect.h
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimationEffect.h
@@ -31,38 +31,30 @@
#ifndef AnimationEffect_h
#define AnimationEffect_h
-#include "CSSPropertyNames.h"
+#include "core/CSSPropertyNames.h"
+#include "platform/heap/Handle.h"
#include "wtf/HashMap.h"
#include "wtf/PassOwnPtr.h"
#include "wtf/RefCounted.h"
namespace WebCore {
-class AnimatableValue;
+class Interpolation;
-class AnimationEffect : public RefCounted<AnimationEffect> {
+class AnimationEffect : public RefCountedWillBeGarbageCollectedFinalized<AnimationEffect> {
public:
enum CompositeOperation {
CompositeReplace,
CompositeAdd,
};
- // Encapsulates the value which results from applying a set of composition operations onto an
- // underlying value. It is used to represent the output of the effect phase of the Web
- // Animations model.
- class CompositableValue : public RefCounted<CompositableValue> {
- public:
- virtual ~CompositableValue() { }
- virtual bool dependsOnUnderlyingValue() const = 0;
- virtual PassRefPtr<AnimatableValue> compositeOnto(const AnimatableValue*) const = 0;
- };
virtual ~AnimationEffect() { }
- typedef HashMap<CSSPropertyID, RefPtr<CompositableValue> > CompositableValueMap;
- typedef Vector<std::pair<CSSPropertyID, RefPtr<CompositableValue> > > CompositableValueList;
- virtual PassOwnPtr<CompositableValueList> sample(int iteration, double fraction) const = 0;
+ virtual PassOwnPtrWillBeRawPtr<WillBeHeapVector<RefPtrWillBeMember<Interpolation> > > sample(int iteration, double fraction, double iterationDuration) const = 0;
virtual bool affects(CSSPropertyID) { return false; };
- virtual bool isKeyframeAnimationEffect() const { return false; }
+ virtual bool isKeyframeEffectModel() const { return false; }
+
+ virtual void trace(Visitor*) { }
};
} // namespace WebCore
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimationEffect.idl b/chromium/third_party/WebKit/Source/core/animation/AnimationEffect.idl
new file mode 100644
index 00000000000..f5dc6ce2f57
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimationEffect.idl
@@ -0,0 +1,10 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+[
+ RuntimeEnabled=WebAnimationsAPI,
+ NoInterfaceObject,
+ WillBeGarbageCollected
+] interface AnimationEffect {
+};
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimationHelpers.h b/chromium/third_party/WebKit/Source/core/animation/AnimationHelpers.h
new file mode 100644
index 00000000000..daeb2d5b48f
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimationHelpers.h
@@ -0,0 +1,33 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef AnimationHelpers_h
+#define AnimationHelpers_h
+
+#include "core/css/parser/BisonCSSParser.h"
+#include "wtf/text/StringBuilder.h"
+
+namespace WebCore {
+
+static inline CSSPropertyID camelCaseCSSPropertyNameToID(const String& propertyName)
+{
+ if (propertyName.find('-') != kNotFound)
+ return CSSPropertyInvalid;
+
+ StringBuilder builder;
+ size_t position = 0;
+ size_t end;
+ while ((end = propertyName.find(isASCIIUpper, position)) != kNotFound) {
+ builder.append(propertyName.substring(position, end - position) + "-" + toASCIILower((propertyName)[end]));
+ position = end + 1;
+ }
+ builder.append(propertyName.substring(position));
+ // Doesn't handle prefixed properties.
+ CSSPropertyID id = cssPropertyID(builder.toString());
+ return id;
+}
+
+} // namespace WebCore
+
+#endif // AnimationHelpers_h
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimationHelpersTest.cpp b/chromium/third_party/WebKit/Source/core/animation/AnimationHelpersTest.cpp
new file mode 100644
index 00000000000..df3727f7d98
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimationHelpersTest.cpp
@@ -0,0 +1,24 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "config.h"
+#include "core/animation/AnimationHelpers.h"
+
+#include <gtest/gtest.h>
+
+namespace WebCore {
+
+TEST(AnimationAnimationHelpersTest, ParseCamelCasePropertyNames)
+{
+ EXPECT_EQ(CSSPropertyInvalid, camelCaseCSSPropertyNameToID(String("line-height")));
+ EXPECT_EQ(CSSPropertyLineHeight, camelCaseCSSPropertyNameToID(String("lineHeight")));
+ EXPECT_EQ(CSSPropertyBorderTopWidth, camelCaseCSSPropertyNameToID(String("borderTopWidth")));
+ EXPECT_EQ(CSSPropertyWidth, camelCaseCSSPropertyNameToID(String("width")));
+ EXPECT_EQ(CSSPropertyInvalid, camelCaseCSSPropertyNameToID(String("Width")));
+ EXPECT_EQ(CSSPropertyInvalid, camelCaseCSSPropertyNameToID(String("-webkit-transform")));
+ EXPECT_EQ(CSSPropertyInvalid, camelCaseCSSPropertyNameToID(String("webkitTransform")));
+ EXPECT_EQ(CSSPropertyInvalid, camelCaseCSSPropertyNameToID(String("cssFloat")));
+}
+
+} // namespace WebCore
diff --git a/chromium/third_party/WebKit/Source/core/animation/TimedItem.cpp b/chromium/third_party/WebKit/Source/core/animation/AnimationNode.cpp
index 3b7aa948c1f..1e5f863074b 100644
--- a/chromium/third_party/WebKit/Source/core/animation/TimedItem.cpp
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimationNode.cpp
@@ -29,120 +29,167 @@
*/
#include "config.h"
-#include "core/animation/TimedItem.h"
+#include "core/animation/AnimationNode.h"
-#include "core/animation/Player.h"
-#include "core/animation/TimedItemCalculations.h"
+#include "core/animation/AnimationNodeTiming.h"
+#include "core/animation/AnimationPlayer.h"
+#include "core/animation/TimingCalculations.h"
namespace WebCore {
-TimedItem::TimedItem(const Timing& timing, PassOwnPtr<EventDelegate> eventDelegate)
- : m_parent(0)
+namespace {
+
+Timing::FillMode resolvedFillMode(Timing::FillMode fillMode, bool isAnimation)
+{
+ if (fillMode != Timing::FillModeAuto)
+ return fillMode;
+ if (isAnimation)
+ return Timing::FillModeNone;
+ return Timing::FillModeBoth;
+}
+
+} // namespace
+
+AnimationNode::AnimationNode(const Timing& timing, PassOwnPtr<EventDelegate> eventDelegate)
+ : m_parent(nullptr)
, m_startTime(0)
- , m_player(0)
- , m_specified(timing)
+ , m_player(nullptr)
+ , m_timing(timing)
, m_eventDelegate(eventDelegate)
, m_calculated()
- , m_isFirstSample(true)
, m_needsUpdate(true)
, m_lastUpdateTime(nullValue())
{
- m_specified.assertValid();
+ m_timing.assertValid();
+}
+
+double AnimationNode::iterationDuration() const
+{
+ double result = std::isnan(m_timing.iterationDuration) ? intrinsicIterationDuration() : m_timing.iterationDuration;
+ ASSERT(result >= 0);
+ return result;
+}
+
+double AnimationNode::repeatedDuration() const
+{
+ const double result = multiplyZeroAlwaysGivesZero(iterationDuration(), m_timing.iterationCount);
+ ASSERT(result >= 0);
+ return result;
+}
+
+double AnimationNode::activeDurationInternal() const
+{
+ const double result = m_timing.playbackRate
+ ? repeatedDuration() / std::abs(m_timing.playbackRate)
+ : std::numeric_limits<double>::infinity();
+ ASSERT(result >= 0);
+ return result;
}
-bool TimedItem::updateInheritedTime(double inheritedTime) const
+void AnimationNode::updateSpecifiedTiming(const Timing& timing)
+{
+ // FIXME: Test whether the timing is actually different?
+ m_timing = timing;
+ invalidate();
+ if (m_player)
+ m_player->setOutdated();
+ specifiedTimingChanged();
+}
+
+void AnimationNode::updateInheritedTime(double inheritedTime, TimingUpdateReason reason) const
{
bool needsUpdate = m_needsUpdate || (m_lastUpdateTime != inheritedTime && !(isNull(m_lastUpdateTime) && isNull(inheritedTime)));
m_needsUpdate = false;
m_lastUpdateTime = inheritedTime;
- const double previousIteration = m_calculated.currentIteration;
- const Phase previousPhase = m_calculated.phase;
-
const double localTime = inheritedTime - m_startTime;
double timeToNextIteration = std::numeric_limits<double>::infinity();
if (needsUpdate) {
- const double iterationDuration = m_specified.hasIterationDuration
- ? m_specified.iterationDuration
- : intrinsicIterationDuration();
- ASSERT(iterationDuration >= 0);
-
- // When iterationDuration = 0 and iterationCount = infinity, or vice-
- // versa, repeatedDuration should be 0, not NaN as operator*() would give.
- // FIXME: The spec is unclear about this.
- const double repeatedDuration = multiplyZeroAlwaysGivesZero(iterationDuration, m_specified.iterationCount);
- ASSERT(repeatedDuration >= 0);
- const double activeDuration = m_specified.playbackRate
- ? repeatedDuration / abs(m_specified.playbackRate)
- : std::numeric_limits<double>::infinity();
- ASSERT(activeDuration >= 0);
-
- const Phase currentPhase = calculatePhase(activeDuration, localTime, m_specified);
+ const double activeDuration = this->activeDurationInternal();
+
+ const Phase currentPhase = calculatePhase(activeDuration, localTime, m_timing);
// FIXME: parentPhase depends on groups being implemented.
- const TimedItem::Phase parentPhase = TimedItem::PhaseActive;
- const double activeTime = calculateActiveTime(activeDuration, localTime, parentPhase, currentPhase, m_specified);
+ const AnimationNode::Phase parentPhase = AnimationNode::PhaseActive;
+ const double activeTime = calculateActiveTime(activeDuration, resolvedFillMode(m_timing.fillMode, isAnimation()), localTime, parentPhase, currentPhase, m_timing);
double currentIteration;
double timeFraction;
- if (iterationDuration) {
- const double startOffset = multiplyZeroAlwaysGivesZero(m_specified.iterationStart, iterationDuration);
+ if (const double iterationDuration = this->iterationDuration()) {
+ const double startOffset = multiplyZeroAlwaysGivesZero(m_timing.iterationStart, iterationDuration);
ASSERT(startOffset >= 0);
- const double scaledActiveTime = calculateScaledActiveTime(activeDuration, activeTime, startOffset, m_specified);
- const double iterationTime = calculateIterationTime(iterationDuration, repeatedDuration, scaledActiveTime, startOffset, m_specified);
+ const double scaledActiveTime = calculateScaledActiveTime(activeDuration, activeTime, startOffset, m_timing);
+ const double iterationTime = calculateIterationTime(iterationDuration, repeatedDuration(), scaledActiveTime, startOffset, m_timing);
- currentIteration = calculateCurrentIteration(iterationDuration, iterationTime, scaledActiveTime, m_specified);
- timeFraction = calculateTransformedTime(currentIteration, iterationDuration, iterationTime, m_specified) / iterationDuration;
+ currentIteration = calculateCurrentIteration(iterationDuration, iterationTime, scaledActiveTime, m_timing);
+ timeFraction = calculateTransformedTime(currentIteration, iterationDuration, iterationTime, m_timing) / iterationDuration;
if (!isNull(iterationTime)) {
- timeToNextIteration = (iterationDuration - iterationTime) / abs(m_specified.playbackRate);
+ timeToNextIteration = (iterationDuration - iterationTime) / std::abs(m_timing.playbackRate);
if (activeDuration - activeTime < timeToNextIteration)
timeToNextIteration = std::numeric_limits<double>::infinity();
}
} else {
const double localIterationDuration = 1;
- const double localRepeatedDuration = localIterationDuration * m_specified.iterationCount;
+ const double localRepeatedDuration = localIterationDuration * m_timing.iterationCount;
ASSERT(localRepeatedDuration >= 0);
- const double localActiveDuration = m_specified.playbackRate ? localRepeatedDuration / abs(m_specified.playbackRate) : std::numeric_limits<double>::infinity();
+ const double localActiveDuration = m_timing.playbackRate ? localRepeatedDuration / std::abs(m_timing.playbackRate) : std::numeric_limits<double>::infinity();
ASSERT(localActiveDuration >= 0);
- const double localLocalTime = localTime < m_specified.startDelay ? localTime : localActiveDuration + m_specified.startDelay;
- const TimedItem::Phase localCurrentPhase = calculatePhase(localActiveDuration, localLocalTime, m_specified);
- const double localActiveTime = calculateActiveTime(localActiveDuration, localLocalTime, parentPhase, localCurrentPhase, m_specified);
- const double startOffset = m_specified.iterationStart * localIterationDuration;
+ const double localLocalTime = localTime < m_timing.startDelay ? localTime : localActiveDuration + m_timing.startDelay;
+ const AnimationNode::Phase localCurrentPhase = calculatePhase(localActiveDuration, localLocalTime, m_timing);
+ const double localActiveTime = calculateActiveTime(localActiveDuration, resolvedFillMode(m_timing.fillMode, isAnimation()), localLocalTime, parentPhase, localCurrentPhase, m_timing);
+ const double startOffset = m_timing.iterationStart * localIterationDuration;
ASSERT(startOffset >= 0);
- const double scaledActiveTime = calculateScaledActiveTime(localActiveDuration, localActiveTime, startOffset, m_specified);
- const double iterationTime = calculateIterationTime(localIterationDuration, localRepeatedDuration, scaledActiveTime, startOffset, m_specified);
+ const double scaledActiveTime = calculateScaledActiveTime(localActiveDuration, localActiveTime, startOffset, m_timing);
+ const double iterationTime = calculateIterationTime(localIterationDuration, localRepeatedDuration, scaledActiveTime, startOffset, m_timing);
- currentIteration = calculateCurrentIteration(localIterationDuration, iterationTime, scaledActiveTime, m_specified);
- timeFraction = calculateTransformedTime(currentIteration, localIterationDuration, iterationTime, m_specified);
+ currentIteration = calculateCurrentIteration(localIterationDuration, iterationTime, scaledActiveTime, m_timing);
+ timeFraction = calculateTransformedTime(currentIteration, localIterationDuration, iterationTime, m_timing);
}
m_calculated.currentIteration = currentIteration;
- m_calculated.activeDuration = activeDuration;
m_calculated.timeFraction = timeFraction;
m_calculated.phase = currentPhase;
m_calculated.isInEffect = !isNull(activeTime);
m_calculated.isInPlay = phase() == PhaseActive && (!m_parent || m_parent->isInPlay());
m_calculated.isCurrent = phase() == PhaseBefore || isInPlay() || (m_parent && m_parent->isCurrent());
+ m_calculated.localTime = m_lastUpdateTime - m_startTime;
}
// Test for events even if timing didn't need an update as the player may have gained a start time.
// FIXME: Refactor so that we can ASSERT(m_player) here, this is currently required to be nullable for testing.
- if (!m_player || m_player->hasStartTime()) {
- // This logic is specific to CSS animation events and assumes that all
- // animations start after the DocumentTimeline has started.
- if (m_eventDelegate && (m_isFirstSample || previousPhase != phase() || (phase() == PhaseActive && previousIteration != m_calculated.currentIteration)))
- m_eventDelegate->onEventCondition(this, m_isFirstSample, previousPhase, previousIteration);
- m_isFirstSample = false;
+ if (reason == TimingUpdateForAnimationFrame && (!m_player || m_player->hasStartTime())) {
+ if (m_eventDelegate)
+ m_eventDelegate->onEventCondition(this);
}
- bool didTriggerStyleRecalc = false;
if (needsUpdate) {
// FIXME: This probably shouldn't be recursive.
- didTriggerStyleRecalc = updateChildrenAndEffects();
- m_calculated.timeToEffectChange = calculateTimeToEffectChange(localTime, timeToNextIteration);
+ updateChildrenAndEffects();
+ m_calculated.timeToForwardsEffectChange = calculateTimeToEffectChange(true, localTime, timeToNextIteration);
+ m_calculated.timeToReverseEffectChange = calculateTimeToEffectChange(false, localTime, timeToNextIteration);
}
- return didTriggerStyleRecalc;
+}
+
+const AnimationNode::CalculatedTiming& AnimationNode::ensureCalculated() const
+{
+ if (!m_player)
+ return m_calculated;
+ if (m_player->outdated())
+ m_player->update(TimingUpdateOnDemand);
+ ASSERT(!m_player->outdated());
+ return m_calculated;
+}
+
+PassRefPtrWillBeRawPtr<AnimationNodeTiming> AnimationNode::timing()
+{
+ return AnimationNodeTiming::create(this);
+}
+
+void AnimationNode::trace(Visitor* visitor)
+{
+ visitor->trace(m_parent);
+ visitor->trace(m_player);
}
} // namespace WebCore
diff --git a/chromium/third_party/WebKit/Source/core/animation/TimedItem.h b/chromium/third_party/WebKit/Source/core/animation/AnimationNode.h
index 82da5133f58..4c548541b75 100644
--- a/chromium/third_party/WebKit/Source/core/animation/TimedItem.h
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimationNode.h
@@ -28,18 +28,25 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef TimedItem_h
-#define TimedItem_h
+#ifndef AnimationNode_h
+#define AnimationNode_h
#include "core/animation/Timing.h"
+#include "platform/heap/Handle.h"
#include "wtf/OwnPtr.h"
#include "wtf/PassOwnPtr.h"
#include "wtf/RefCounted.h"
namespace WebCore {
-class Player;
-class TimedItem;
+class AnimationPlayer;
+class AnimationNode;
+class AnimationNodeTiming;
+
+enum TimingUpdateReason {
+ TimingUpdateOnDemand,
+ TimingUpdateForAnimationFrame
+};
static inline bool isNull(double value)
{
@@ -51,8 +58,8 @@ static inline double nullValue()
return std::numeric_limits<double>::quiet_NaN();
}
-class TimedItem : public RefCounted<TimedItem> {
- friend class Player; // Calls attach/detach, updateInheritedTime.
+class AnimationNode : public RefCountedWillBeGarbageCollectedFinalized<AnimationNode> {
+ friend class AnimationPlayer; // Calls attach/detach, updateInheritedTime.
public:
// Note that logic in CSSAnimations depends on the order of these values.
enum Phase {
@@ -65,10 +72,10 @@ public:
class EventDelegate {
public:
virtual ~EventDelegate() { };
- virtual void onEventCondition(const TimedItem*, bool isFirstSample, Phase previousPhase, double previousIteration) = 0;
+ virtual void onEventCondition(const AnimationNode*) = 0;
};
- virtual ~TimedItem() { }
+ virtual ~AnimationNode() { }
virtual bool isAnimation() const { return false; }
@@ -76,71 +83,87 @@ public:
bool isCurrent() const { return ensureCalculated().isCurrent; }
bool isInEffect() const { return ensureCalculated().isInEffect; }
bool isInPlay() const { return ensureCalculated().isInPlay; }
- double timeToEffectChange() const { return ensureCalculated().timeToEffectChange; }
+ double timeToForwardsEffectChange() const { return ensureCalculated().timeToForwardsEffectChange; }
+ double timeToReverseEffectChange() const { return ensureCalculated().timeToReverseEffectChange; }
double currentIteration() const { return ensureCalculated().currentIteration; }
- double activeDuration() const { return ensureCalculated().activeDuration; }
+ double iterationDuration() const;
+
+ // This method returns time in ms as it is unused except via the API.
+ double duration() const { return iterationDuration() * 1000; }
+
+ double activeDuration() const { return activeDurationInternal() * 1000; }
+ double activeDurationInternal() const;
double timeFraction() const { return ensureCalculated().timeFraction; }
- double startTime() const { return m_startTime; }
- const Player* player() const { return m_player; }
- Player* player() { return m_player; }
- const Timing& specified() const { return m_specified; }
+ double startTime() const { return m_startTime * 1000; }
+ double startTimeInternal() const { return m_startTime; }
+ double endTime() const { return endTimeInternal() * 1000; }
+ double endTimeInternal() const { return startTime() + specifiedTiming().startDelay + activeDurationInternal() + specifiedTiming().endDelay; }
+
+ const AnimationPlayer* player() const { return m_player; }
+ AnimationPlayer* player() { return m_player; }
+ AnimationPlayer* player(bool& isNull) { isNull = !m_player; return m_player; }
+ const Timing& specifiedTiming() const { return m_timing; }
+ PassRefPtrWillBeRawPtr<AnimationNodeTiming> timing();
+ void updateSpecifiedTiming(const Timing&);
+
+ // This method returns time in ms as it is unused except via the API.
+ double localTime(bool& isNull) const { isNull = !m_player; return ensureCalculated().localTime * 1000; }
+ double currentIteration(bool& isNull) const { isNull = !ensureCalculated().isInEffect; return ensureCalculated().currentIteration; }
+
+ virtual void trace(Visitor*);
protected:
- TimedItem(const Timing&, PassOwnPtr<EventDelegate> = nullptr);
+ explicit AnimationNode(const Timing&, PassOwnPtr<EventDelegate> = nullptr);
- // When TimedItem receives a new inherited time via updateInheritedTime
+ // When AnimationNode receives a new inherited time via updateInheritedTime
// it will (if necessary) recalculate timings and (if necessary) call
// updateChildrenAndEffects.
- // Returns whether style recalc was triggered.
- bool updateInheritedTime(double inheritedTime) const;
+ void updateInheritedTime(double inheritedTime, TimingUpdateReason) const;
void invalidate() const { m_needsUpdate = true; };
+ bool hasEvents() const { return m_eventDelegate; }
+ void clearEventDelegate() { m_eventDelegate = nullptr; }
-private:
- // Returns whether style recalc was triggered.
- virtual bool updateChildrenAndEffects() const = 0;
- virtual double intrinsicIterationDuration() const { return 0; };
- virtual double calculateTimeToEffectChange(double localTime, double timeToNextIteration) const = 0;
- virtual void didAttach() { };
- virtual void willDetach() { };
-
- void attach(Player* player)
+ virtual void attach(AnimationPlayer* player)
{
m_player = player;
- didAttach();
- };
+ }
- void detach()
+ virtual void detach()
{
ASSERT(m_player);
- willDetach();
- m_player = 0;
- };
+ m_player = nullptr;
+ }
+
+ double repeatedDuration() const;
+
+ virtual void updateChildrenAndEffects() const = 0;
+ virtual double intrinsicIterationDuration() const { return 0; };
+ virtual double calculateTimeToEffectChange(bool forwards, double localTime, double timeToNextIteration) const = 0;
+ virtual void specifiedTimingChanged() { }
// FIXME: m_parent and m_startTime are placeholders, they depend on timing groups.
- TimedItem* const m_parent;
+ RawPtrWillBeMember<AnimationNode> m_parent;
const double m_startTime;
- Player* m_player;
- Timing m_specified;
+ RawPtrWillBeMember<AnimationPlayer> m_player;
+ Timing m_timing;
OwnPtr<EventDelegate> m_eventDelegate;
- // FIXME: Should be versioned by monotonic value on player.
mutable struct CalculatedTiming {
- double activeDuration;
Phase phase;
double currentIteration;
double timeFraction;
bool isCurrent;
bool isInEffect;
bool isInPlay;
- double timeToEffectChange;
+ double localTime;
+ double timeToForwardsEffectChange;
+ double timeToReverseEffectChange;
} m_calculated;
- mutable bool m_isFirstSample;
mutable bool m_needsUpdate;
mutable double m_lastUpdateTime;
- // FIXME: Should check the version and reinherit time if inconsistent.
- const CalculatedTiming& ensureCalculated() const { return m_calculated; }
+ const CalculatedTiming& ensureCalculated() const;
};
} // namespace WebCore
diff --git a/chromium/third_party/WebKit/Source/core/animation/css/TransitionTimeline.cpp b/chromium/third_party/WebKit/Source/core/animation/AnimationNode.idl
index 33ec27f2b0b..c04ede67dfc 100644
--- a/chromium/third_party/WebKit/Source/core/animation/css/TransitionTimeline.cpp
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimationNode.idl
@@ -28,25 +28,20 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "config.h"
-#include "core/animation/css/TransitionTimeline.h"
+[
+ RuntimeEnabled=WebAnimationsAPI,
+ WillBeGarbageCollected,
+] interface AnimationNode {
+ // Playback state
+ readonly attribute double? localTime;
+ readonly attribute unsigned long? currentIteration;
-#include "core/animation/ActiveAnimations.h"
-#include "core/animation/AnimationClock.h"
-#include "core/animation/AnimationStack.h"
+ // Calculated timing
+ readonly attribute double startTime;
+ readonly attribute double duration;
+ readonly attribute double activeDuration;
+ readonly attribute double endTime;
-namespace WebCore {
-
-PassRefPtr<TransitionTimeline> TransitionTimeline::create(Document* document, PassOwnPtr<PlatformTiming> timing)
-{
- return adoptRef(new TransitionTimeline(document, timing));
-}
-
-TransitionTimeline::TransitionTimeline(Document* document, PassOwnPtr<PlatformTiming> timing)
- : DocumentTimeline(document, timing)
-{
- setZeroTime(document->animationClock().currentTime());
- document->animationClock().unfreeze();
-}
-
-} // namespace WebCore
+ readonly attribute Timing timing;
+ readonly attribute AnimationPlayer? player;
+};
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimationNodeTest.cpp b/chromium/third_party/WebKit/Source/core/animation/AnimationNodeTest.cpp
new file mode 100644
index 00000000000..944c3c4f63a
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimationNodeTest.cpp
@@ -0,0 +1,775 @@
+/*
+ * Copyright (c) 2013, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "core/animation/AnimationNode.h"
+
+#include <gtest/gtest.h>
+
+using namespace WebCore;
+
+namespace {
+
+class TestAnimationNodeEventDelegate : public AnimationNode::EventDelegate {
+public:
+ virtual void onEventCondition(const AnimationNode* animationNode) OVERRIDE
+ {
+ m_eventTriggered = true;
+
+ }
+ void reset()
+ {
+ m_eventTriggered = false;
+ }
+ bool eventTriggered() { return m_eventTriggered; }
+
+private:
+ bool m_eventTriggered;
+};
+
+class TestAnimationNode : public AnimationNode {
+public:
+ static PassRefPtrWillBeRawPtr<TestAnimationNode> create(const Timing& specified)
+ {
+ return adoptRefWillBeNoop(new TestAnimationNode(specified, new TestAnimationNodeEventDelegate()));
+ }
+
+ void updateInheritedTime(double time)
+ {
+ updateInheritedTime(time, TimingUpdateForAnimationFrame);
+ }
+
+ void updateInheritedTime(double time, TimingUpdateReason reason)
+ {
+ m_eventDelegate->reset();
+ AnimationNode::updateInheritedTime(time, reason);
+ }
+
+ virtual void updateChildrenAndEffects() const OVERRIDE { }
+ void willDetach() { }
+ TestAnimationNodeEventDelegate* eventDelegate() { return m_eventDelegate; }
+ virtual double calculateTimeToEffectChange(bool forwards, double localTime, double timeToNextIteration) const OVERRIDE
+ {
+ m_localTime = localTime;
+ m_timeToNextIteration = timeToNextIteration;
+ return -1;
+ }
+ double takeLocalTime()
+ {
+ const double result = m_localTime;
+ m_localTime = nullValue();
+ return result;
+ }
+
+ double takeTimeToNextIteration()
+ {
+ const double result = m_timeToNextIteration;
+ m_timeToNextIteration = nullValue();
+ return result;
+ }
+
+private:
+ TestAnimationNode(const Timing& specified, TestAnimationNodeEventDelegate* eventDelegate)
+ : AnimationNode(specified, adoptPtr(eventDelegate))
+ , m_eventDelegate(eventDelegate)
+ {
+ }
+
+ TestAnimationNodeEventDelegate* m_eventDelegate;
+ mutable double m_localTime;
+ mutable double m_timeToNextIteration;
+};
+
+TEST(AnimationAnimationNodeTest, Sanity)
+{
+ Timing timing;
+ timing.iterationDuration = 2;
+ RefPtrWillBeRawPtr<TestAnimationNode> animationNode = TestAnimationNode::create(timing);
+
+ EXPECT_EQ(0, animationNode->startTime());
+
+ animationNode->updateInheritedTime(0);
+
+ EXPECT_EQ(AnimationNode::PhaseActive, animationNode->phase());
+ EXPECT_TRUE(animationNode->isInPlay());
+ EXPECT_TRUE(animationNode->isCurrent());
+ EXPECT_TRUE(animationNode->isInEffect());
+ EXPECT_EQ(0, animationNode->currentIteration());
+ EXPECT_EQ(0, animationNode->startTime());
+ EXPECT_EQ(2, animationNode->activeDurationInternal());
+ EXPECT_EQ(0, animationNode->timeFraction());
+
+ animationNode->updateInheritedTime(1);
+
+ EXPECT_EQ(AnimationNode::PhaseActive, animationNode->phase());
+ EXPECT_TRUE(animationNode->isInPlay());
+ EXPECT_TRUE(animationNode->isCurrent());
+ EXPECT_TRUE(animationNode->isInEffect());
+ EXPECT_EQ(0, animationNode->currentIteration());
+ EXPECT_EQ(0, animationNode->startTime());
+ EXPECT_EQ(2, animationNode->activeDurationInternal());
+ EXPECT_EQ(0.5, animationNode->timeFraction());
+
+ animationNode->updateInheritedTime(2);
+
+ EXPECT_EQ(AnimationNode::PhaseAfter, animationNode->phase());
+ EXPECT_FALSE(animationNode->isInPlay());
+ EXPECT_FALSE(animationNode->isCurrent());
+ EXPECT_TRUE(animationNode->isInEffect());
+ EXPECT_EQ(0, animationNode->currentIteration());
+ EXPECT_EQ(0, animationNode->startTime());
+ EXPECT_EQ(2, animationNode->activeDurationInternal());
+ EXPECT_EQ(1, animationNode->timeFraction());
+
+ animationNode->updateInheritedTime(3);
+
+ EXPECT_EQ(AnimationNode::PhaseAfter, animationNode->phase());
+ EXPECT_FALSE(animationNode->isInPlay());
+ EXPECT_FALSE(animationNode->isCurrent());
+ EXPECT_TRUE(animationNode->isInEffect());
+ EXPECT_EQ(0, animationNode->currentIteration());
+ EXPECT_EQ(0, animationNode->startTime());
+ EXPECT_EQ(2, animationNode->activeDurationInternal());
+ EXPECT_EQ(1, animationNode->timeFraction());
+}
+
+TEST(AnimationAnimationNodeTest, FillAuto)
+{
+ Timing timing;
+ timing.iterationDuration = 1;
+ RefPtrWillBeRawPtr<TestAnimationNode> animationNode = TestAnimationNode::create(timing);
+
+ animationNode->updateInheritedTime(-1);
+ EXPECT_EQ(0, animationNode->timeFraction());
+
+ animationNode->updateInheritedTime(2);
+ EXPECT_EQ(1, animationNode->timeFraction());
+}
+
+TEST(AnimationAnimationNodeTest, FillForwards)
+{
+ Timing timing;
+ timing.iterationDuration = 1;
+ timing.fillMode = Timing::FillModeForwards;
+ RefPtrWillBeRawPtr<TestAnimationNode> animationNode = TestAnimationNode::create(timing);
+
+ animationNode->updateInheritedTime(-1);
+ EXPECT_TRUE(isNull(animationNode->timeFraction()));
+
+ animationNode->updateInheritedTime(2);
+ EXPECT_EQ(1, animationNode->timeFraction());
+}
+
+TEST(AnimationAnimationNodeTest, FillBackwards)
+{
+ Timing timing;
+ timing.iterationDuration = 1;
+ timing.fillMode = Timing::FillModeBackwards;
+ RefPtrWillBeRawPtr<TestAnimationNode> animationNode = TestAnimationNode::create(timing);
+
+ animationNode->updateInheritedTime(-1);
+ EXPECT_EQ(0, animationNode->timeFraction());
+
+ animationNode->updateInheritedTime(2);
+ EXPECT_TRUE(isNull(animationNode->timeFraction()));
+}
+
+TEST(AnimationAnimationNodeTest, FillBoth)
+{
+ Timing timing;
+ timing.iterationDuration = 1;
+ timing.fillMode = Timing::FillModeBoth;
+ RefPtrWillBeRawPtr<TestAnimationNode> animationNode = TestAnimationNode::create(timing);
+
+ animationNode->updateInheritedTime(-1);
+ EXPECT_EQ(0, animationNode->timeFraction());
+
+ animationNode->updateInheritedTime(2);
+ EXPECT_EQ(1, animationNode->timeFraction());
+}
+
+TEST(AnimationAnimationNodeTest, StartDelay)
+{
+ Timing timing;
+ timing.iterationDuration = 1;
+ timing.fillMode = Timing::FillModeForwards;
+ timing.startDelay = 0.5;
+ RefPtrWillBeRawPtr<TestAnimationNode> animationNode = TestAnimationNode::create(timing);
+
+ animationNode->updateInheritedTime(0);
+ EXPECT_TRUE(isNull(animationNode->timeFraction()));
+
+ animationNode->updateInheritedTime(0.5);
+ EXPECT_EQ(0, animationNode->timeFraction());
+
+ animationNode->updateInheritedTime(1.5);
+ EXPECT_EQ(1, animationNode->timeFraction());
+}
+
+TEST(AnimationAnimationNodeTest, ZeroIteration)
+{
+ Timing timing;
+ timing.iterationDuration = 1;
+ timing.fillMode = Timing::FillModeForwards;
+ timing.iterationCount = 0;
+ RefPtrWillBeRawPtr<TestAnimationNode> animationNode = TestAnimationNode::create(timing);
+
+ animationNode->updateInheritedTime(-1);
+ EXPECT_EQ(0, animationNode->activeDurationInternal());
+ EXPECT_TRUE(isNull(animationNode->currentIteration()));
+ EXPECT_TRUE(isNull(animationNode->timeFraction()));
+
+ animationNode->updateInheritedTime(0);
+ EXPECT_EQ(0, animationNode->activeDurationInternal());
+ EXPECT_EQ(0, animationNode->currentIteration());
+ EXPECT_EQ(0, animationNode->timeFraction());
+}
+
+TEST(AnimationAnimationNodeTest, InfiniteIteration)
+{
+ Timing timing;
+ timing.iterationDuration = 1;
+ timing.fillMode = Timing::FillModeForwards;
+ timing.iterationCount = std::numeric_limits<double>::infinity();
+ RefPtrWillBeRawPtr<TestAnimationNode> animationNode = TestAnimationNode::create(timing);
+
+ animationNode->updateInheritedTime(-1);
+ EXPECT_TRUE(isNull(animationNode->currentIteration()));
+ EXPECT_TRUE(isNull(animationNode->timeFraction()));
+
+ EXPECT_EQ(std::numeric_limits<double>::infinity(), animationNode->activeDurationInternal());
+
+ animationNode->updateInheritedTime(0);
+ EXPECT_EQ(0, animationNode->currentIteration());
+ EXPECT_EQ(0, animationNode->timeFraction());
+}
+
+TEST(AnimationAnimationNodeTest, Iteration)
+{
+ Timing timing;
+ timing.iterationCount = 2;
+ timing.iterationDuration = 2;
+ RefPtrWillBeRawPtr<TestAnimationNode> animationNode = TestAnimationNode::create(timing);
+
+ animationNode->updateInheritedTime(0);
+ EXPECT_EQ(0, animationNode->currentIteration());
+ EXPECT_EQ(0, animationNode->timeFraction());
+
+ animationNode->updateInheritedTime(1);
+ EXPECT_EQ(0, animationNode->currentIteration());
+ EXPECT_EQ(0.5, animationNode->timeFraction());
+
+ animationNode->updateInheritedTime(2);
+ EXPECT_EQ(1, animationNode->currentIteration());
+ EXPECT_EQ(0, animationNode->timeFraction());
+
+ animationNode->updateInheritedTime(2);
+ EXPECT_EQ(1, animationNode->currentIteration());
+ EXPECT_EQ(0, animationNode->timeFraction());
+
+ animationNode->updateInheritedTime(5);
+ EXPECT_EQ(1, animationNode->currentIteration());
+ EXPECT_EQ(1, animationNode->timeFraction());
+}
+
+TEST(AnimationAnimationNodeTest, IterationStart)
+{
+ Timing timing;
+ timing.iterationStart = 1.2;
+ timing.iterationCount = 2.2;
+ timing.iterationDuration = 1;
+ timing.fillMode = Timing::FillModeBoth;
+ RefPtrWillBeRawPtr<TestAnimationNode> animationNode = TestAnimationNode::create(timing);
+
+ animationNode->updateInheritedTime(-1);
+ EXPECT_EQ(1, animationNode->currentIteration());
+ EXPECT_NEAR(0.2, animationNode->timeFraction(), 0.000000000000001);
+
+ animationNode->updateInheritedTime(0);
+ EXPECT_EQ(1, animationNode->currentIteration());
+ EXPECT_NEAR(0.2, animationNode->timeFraction(), 0.000000000000001);
+
+ animationNode->updateInheritedTime(10);
+ EXPECT_EQ(3, animationNode->currentIteration());
+ EXPECT_NEAR(0.4, animationNode->timeFraction(), 0.000000000000001);
+}
+
+TEST(AnimationAnimationNodeTest, IterationAlternate)
+{
+ Timing timing;
+ timing.iterationCount = 10;
+ timing.iterationDuration = 1;
+ timing.direction = Timing::PlaybackDirectionAlternate;
+ RefPtrWillBeRawPtr<TestAnimationNode> animationNode = TestAnimationNode::create(timing);
+
+ animationNode->updateInheritedTime(0.75);
+ EXPECT_EQ(0, animationNode->currentIteration());
+ EXPECT_EQ(0.75, animationNode->timeFraction());
+
+ animationNode->updateInheritedTime(1.75);
+ EXPECT_EQ(1, animationNode->currentIteration());
+ EXPECT_EQ(0.25, animationNode->timeFraction());
+
+ animationNode->updateInheritedTime(2.75);
+ EXPECT_EQ(2, animationNode->currentIteration());
+ EXPECT_EQ(0.75, animationNode->timeFraction());
+}
+
+TEST(AnimationAnimationNodeTest, IterationAlternateReverse)
+{
+ Timing timing;
+ timing.iterationCount = 10;
+ timing.iterationDuration = 1;
+ timing.direction = Timing::PlaybackDirectionAlternateReverse;
+ RefPtrWillBeRawPtr<TestAnimationNode> animationNode = TestAnimationNode::create(timing);
+
+ animationNode->updateInheritedTime(0.75);
+ EXPECT_EQ(0, animationNode->currentIteration());
+ EXPECT_EQ(0.25, animationNode->timeFraction());
+
+ animationNode->updateInheritedTime(1.75);
+ EXPECT_EQ(1, animationNode->currentIteration());
+ EXPECT_EQ(0.75, animationNode->timeFraction());
+
+ animationNode->updateInheritedTime(2.75);
+ EXPECT_EQ(2, animationNode->currentIteration());
+ EXPECT_EQ(0.25, animationNode->timeFraction());
+}
+
+TEST(AnimationAnimationNodeTest, ZeroDurationSanity)
+{
+ Timing timing;
+ RefPtrWillBeRawPtr<TestAnimationNode> animationNode = TestAnimationNode::create(timing);
+
+ EXPECT_EQ(0, animationNode->startTime());
+
+ animationNode->updateInheritedTime(0);
+
+ EXPECT_EQ(AnimationNode::PhaseAfter, animationNode->phase());
+ EXPECT_FALSE(animationNode->isInPlay());
+ EXPECT_FALSE(animationNode->isCurrent());
+ EXPECT_TRUE(animationNode->isInEffect());
+ EXPECT_EQ(0, animationNode->currentIteration());
+ EXPECT_EQ(0, animationNode->startTime());
+ EXPECT_EQ(0, animationNode->activeDurationInternal());
+ EXPECT_EQ(1, animationNode->timeFraction());
+
+ animationNode->updateInheritedTime(1);
+
+ EXPECT_EQ(AnimationNode::PhaseAfter, animationNode->phase());
+ EXPECT_FALSE(animationNode->isInPlay());
+ EXPECT_FALSE(animationNode->isCurrent());
+ EXPECT_TRUE(animationNode->isInEffect());
+ EXPECT_EQ(0, animationNode->currentIteration());
+ EXPECT_EQ(0, animationNode->startTime());
+ EXPECT_EQ(0, animationNode->activeDurationInternal());
+ EXPECT_EQ(1, animationNode->timeFraction());
+}
+
+TEST(AnimationAnimationNodeTest, ZeroDurationFillForwards)
+{
+ Timing timing;
+ timing.fillMode = Timing::FillModeForwards;
+ RefPtrWillBeRawPtr<TestAnimationNode> animationNode = TestAnimationNode::create(timing);
+
+ animationNode->updateInheritedTime(-1);
+ EXPECT_TRUE(isNull(animationNode->timeFraction()));
+
+ animationNode->updateInheritedTime(0);
+ EXPECT_EQ(1, animationNode->timeFraction());
+
+ animationNode->updateInheritedTime(1);
+ EXPECT_EQ(1, animationNode->timeFraction());
+}
+
+TEST(AnimationAnimationNodeTest, ZeroDurationFillBackwards)
+{
+ Timing timing;
+ timing.fillMode = Timing::FillModeBackwards;
+ RefPtrWillBeRawPtr<TestAnimationNode> animationNode = TestAnimationNode::create(timing);
+
+ animationNode->updateInheritedTime(-1);
+ EXPECT_EQ(0, animationNode->timeFraction());
+
+ animationNode->updateInheritedTime(0);
+ EXPECT_TRUE(isNull(animationNode->timeFraction()));
+
+ animationNode->updateInheritedTime(1);
+ EXPECT_TRUE(isNull(animationNode->timeFraction()));
+}
+
+TEST(AnimationAnimationNodeTest, ZeroDurationFillBoth)
+{
+ Timing timing;
+ timing.fillMode = Timing::FillModeBoth;
+ RefPtrWillBeRawPtr<TestAnimationNode> animationNode = TestAnimationNode::create(timing);
+
+ animationNode->updateInheritedTime(-1);
+ EXPECT_EQ(0, animationNode->timeFraction());
+
+ animationNode->updateInheritedTime(0);
+ EXPECT_EQ(1, animationNode->timeFraction());
+
+ animationNode->updateInheritedTime(1);
+ EXPECT_EQ(1, animationNode->timeFraction());
+}
+
+TEST(AnimationAnimationNodeTest, ZeroDurationStartDelay)
+{
+ Timing timing;
+ timing.fillMode = Timing::FillModeForwards;
+ timing.startDelay = 0.5;
+ RefPtrWillBeRawPtr<TestAnimationNode> animationNode = TestAnimationNode::create(timing);
+
+ animationNode->updateInheritedTime(0);
+ EXPECT_TRUE(isNull(animationNode->timeFraction()));
+
+ animationNode->updateInheritedTime(0.5);
+ EXPECT_EQ(1, animationNode->timeFraction());
+
+ animationNode->updateInheritedTime(1.5);
+ EXPECT_EQ(1, animationNode->timeFraction());
+}
+
+TEST(AnimationAnimationNodeTest, ZeroDurationIterationStartAndCount)
+{
+ Timing timing;
+ timing.iterationStart = 0.1;
+ timing.iterationCount = 0.2;
+ timing.fillMode = Timing::FillModeBoth;
+ timing.startDelay = 0.3;
+ RefPtrWillBeRawPtr<TestAnimationNode> animationNode = TestAnimationNode::create(timing);
+
+ animationNode->updateInheritedTime(0);
+ EXPECT_EQ(0.1, animationNode->timeFraction());
+
+ animationNode->updateInheritedTime(0.3);
+ EXPECT_DOUBLE_EQ(0.3, animationNode->timeFraction());
+
+ animationNode->updateInheritedTime(1);
+ EXPECT_DOUBLE_EQ(0.3, animationNode->timeFraction());
+}
+
+// FIXME: Needs specification work.
+TEST(AnimationAnimationNodeTest, ZeroDurationInfiniteIteration)
+{
+ Timing timing;
+ timing.fillMode = Timing::FillModeForwards;
+ timing.iterationCount = std::numeric_limits<double>::infinity();
+ RefPtrWillBeRawPtr<TestAnimationNode> animationNode = TestAnimationNode::create(timing);
+
+ animationNode->updateInheritedTime(-1);
+ EXPECT_EQ(0, animationNode->activeDurationInternal());
+ EXPECT_TRUE(isNull(animationNode->currentIteration()));
+ EXPECT_TRUE(isNull(animationNode->timeFraction()));
+
+ animationNode->updateInheritedTime(0);
+ EXPECT_EQ(0, animationNode->activeDurationInternal());
+ EXPECT_EQ(std::numeric_limits<double>::infinity(), animationNode->currentIteration());
+ EXPECT_EQ(1, animationNode->timeFraction());
+}
+
+TEST(AnimationAnimationNodeTest, ZeroDurationIteration)
+{
+ Timing timing;
+ timing.fillMode = Timing::FillModeForwards;
+ timing.iterationCount = 2;
+ RefPtrWillBeRawPtr<TestAnimationNode> animationNode = TestAnimationNode::create(timing);
+
+ animationNode->updateInheritedTime(-1);
+ EXPECT_TRUE(isNull(animationNode->currentIteration()));
+ EXPECT_TRUE(isNull(animationNode->timeFraction()));
+
+ animationNode->updateInheritedTime(0);
+ EXPECT_EQ(1, animationNode->currentIteration());
+ EXPECT_EQ(1, animationNode->timeFraction());
+
+ animationNode->updateInheritedTime(1);
+ EXPECT_EQ(1, animationNode->currentIteration());
+ EXPECT_EQ(1, animationNode->timeFraction());
+}
+
+TEST(AnimationAnimationNodeTest, ZeroDurationIterationStart)
+{
+ Timing timing;
+ timing.iterationStart = 1.2;
+ timing.iterationCount = 2.2;
+ timing.fillMode = Timing::FillModeBoth;
+ RefPtrWillBeRawPtr<TestAnimationNode> animationNode = TestAnimationNode::create(timing);
+
+ animationNode->updateInheritedTime(-1);
+ EXPECT_EQ(1, animationNode->currentIteration());
+ EXPECT_NEAR(0.2, animationNode->timeFraction(), 0.000000000000001);
+
+ animationNode->updateInheritedTime(0);
+ EXPECT_EQ(3, animationNode->currentIteration());
+ EXPECT_NEAR(0.4, animationNode->timeFraction(), 0.000000000000001);
+
+ animationNode->updateInheritedTime(10);
+ EXPECT_EQ(3, animationNode->currentIteration());
+ EXPECT_NEAR(0.4, animationNode->timeFraction(), 0.000000000000001);
+}
+
+TEST(AnimationAnimationNodeTest, ZeroDurationIterationAlternate)
+{
+ Timing timing;
+ timing.fillMode = Timing::FillModeForwards;
+ timing.iterationCount = 2;
+ timing.direction = Timing::PlaybackDirectionAlternate;
+ RefPtrWillBeRawPtr<TestAnimationNode> animationNode = TestAnimationNode::create(timing);
+
+ animationNode->updateInheritedTime(-1);
+ EXPECT_TRUE(isNull(animationNode->currentIteration()));
+ EXPECT_TRUE(isNull(animationNode->timeFraction()));
+
+ animationNode->updateInheritedTime(0);
+ EXPECT_EQ(1, animationNode->currentIteration());
+ EXPECT_EQ(0, animationNode->timeFraction());
+
+ animationNode->updateInheritedTime(1);
+ EXPECT_EQ(1, animationNode->currentIteration());
+ EXPECT_EQ(0, animationNode->timeFraction());
+}
+
+TEST(AnimationAnimationNodeTest, ZeroDurationIterationAlternateReverse)
+{
+ Timing timing;
+ timing.fillMode = Timing::FillModeForwards;
+ timing.iterationCount = 2;
+ timing.direction = Timing::PlaybackDirectionAlternateReverse;
+ RefPtrWillBeRawPtr<TestAnimationNode> animationNode = TestAnimationNode::create(timing);
+
+ animationNode->updateInheritedTime(-1);
+ EXPECT_TRUE(isNull(animationNode->currentIteration()));
+ EXPECT_TRUE(isNull(animationNode->timeFraction()));
+
+ animationNode->updateInheritedTime(0);
+ EXPECT_EQ(1, animationNode->currentIteration());
+ EXPECT_EQ(1, animationNode->timeFraction());
+
+ animationNode->updateInheritedTime(1);
+ EXPECT_EQ(1, animationNode->currentIteration());
+ EXPECT_EQ(1, animationNode->timeFraction());
+}
+
+TEST(AnimationAnimationNodeTest, InfiniteDurationSanity)
+{
+ Timing timing;
+ timing.iterationDuration = std::numeric_limits<double>::infinity();
+ timing.iterationCount = 1;
+ RefPtrWillBeRawPtr<TestAnimationNode> animationNode = TestAnimationNode::create(timing);
+
+ EXPECT_EQ(0, animationNode->startTime());
+
+ animationNode->updateInheritedTime(0);
+
+ EXPECT_EQ(std::numeric_limits<double>::infinity(), animationNode->activeDurationInternal());
+ EXPECT_EQ(AnimationNode::PhaseActive, animationNode->phase());
+ EXPECT_TRUE(animationNode->isInPlay());
+ EXPECT_TRUE(animationNode->isCurrent());
+ EXPECT_TRUE(animationNode->isInEffect());
+ EXPECT_EQ(0, animationNode->currentIteration());
+ EXPECT_EQ(0, animationNode->timeFraction());
+
+ animationNode->updateInheritedTime(1);
+
+ EXPECT_EQ(std::numeric_limits<double>::infinity(), animationNode->activeDurationInternal());
+ EXPECT_EQ(AnimationNode::PhaseActive, animationNode->phase());
+ EXPECT_TRUE(animationNode->isInPlay());
+ EXPECT_TRUE(animationNode->isCurrent());
+ EXPECT_TRUE(animationNode->isInEffect());
+ EXPECT_EQ(0, animationNode->currentIteration());
+ EXPECT_EQ(0, animationNode->timeFraction());
+}
+
+// FIXME: Needs specification work.
+TEST(AnimationAnimationNodeTest, InfiniteDurationZeroIterations)
+{
+ Timing timing;
+ timing.iterationDuration = std::numeric_limits<double>::infinity();
+ timing.iterationCount = 0;
+ RefPtrWillBeRawPtr<TestAnimationNode> animationNode = TestAnimationNode::create(timing);
+
+ EXPECT_EQ(0, animationNode->startTime());
+
+ animationNode->updateInheritedTime(0);
+
+ EXPECT_EQ(0, animationNode->activeDurationInternal());
+ EXPECT_EQ(AnimationNode::PhaseAfter, animationNode->phase());
+ EXPECT_FALSE(animationNode->isInPlay());
+ EXPECT_FALSE(animationNode->isCurrent());
+ EXPECT_TRUE(animationNode->isInEffect());
+ EXPECT_EQ(0, animationNode->currentIteration());
+ EXPECT_EQ(0, animationNode->timeFraction());
+
+ animationNode->updateInheritedTime(1);
+
+ EXPECT_EQ(AnimationNode::PhaseAfter, animationNode->phase());
+ EXPECT_EQ(AnimationNode::PhaseAfter, animationNode->phase());
+ EXPECT_FALSE(animationNode->isInPlay());
+ EXPECT_FALSE(animationNode->isCurrent());
+ EXPECT_TRUE(animationNode->isInEffect());
+ EXPECT_EQ(0, animationNode->currentIteration());
+ EXPECT_EQ(0, animationNode->timeFraction());
+}
+
+TEST(AnimationAnimationNodeTest, InfiniteDurationInfiniteIterations)
+{
+ Timing timing;
+ timing.iterationDuration = std::numeric_limits<double>::infinity();
+ timing.iterationCount = std::numeric_limits<double>::infinity();
+ RefPtrWillBeRawPtr<TestAnimationNode> animationNode = TestAnimationNode::create(timing);
+
+ EXPECT_EQ(0, animationNode->startTime());
+
+ animationNode->updateInheritedTime(0);
+
+ EXPECT_EQ(std::numeric_limits<double>::infinity(), animationNode->activeDurationInternal());
+ EXPECT_EQ(AnimationNode::PhaseActive, animationNode->phase());
+ EXPECT_TRUE(animationNode->isInPlay());
+ EXPECT_TRUE(animationNode->isCurrent());
+ EXPECT_TRUE(animationNode->isInEffect());
+ EXPECT_EQ(0, animationNode->currentIteration());
+ EXPECT_EQ(0, animationNode->timeFraction());
+
+ animationNode->updateInheritedTime(1);
+
+ EXPECT_EQ(std::numeric_limits<double>::infinity(), animationNode->activeDurationInternal());
+ EXPECT_EQ(AnimationNode::PhaseActive, animationNode->phase());
+ EXPECT_TRUE(animationNode->isInPlay());
+ EXPECT_TRUE(animationNode->isCurrent());
+ EXPECT_TRUE(animationNode->isInEffect());
+ EXPECT_EQ(0, animationNode->currentIteration());
+ EXPECT_EQ(0, animationNode->timeFraction());
+}
+
+TEST(AnimationAnimationNodeTest, InfiniteDurationZeroPlaybackRate)
+{
+ Timing timing;
+ timing.iterationDuration = std::numeric_limits<double>::infinity();
+ timing.playbackRate = 0;
+ RefPtrWillBeRawPtr<TestAnimationNode> animationNode = TestAnimationNode::create(timing);
+
+ EXPECT_EQ(0, animationNode->startTime());
+
+ animationNode->updateInheritedTime(0);
+
+ EXPECT_EQ(std::numeric_limits<double>::infinity(), animationNode->activeDurationInternal());
+ EXPECT_EQ(AnimationNode::PhaseActive, animationNode->phase());
+ EXPECT_TRUE(animationNode->isInPlay());
+ EXPECT_TRUE(animationNode->isCurrent());
+ EXPECT_TRUE(animationNode->isInEffect());
+ EXPECT_EQ(0, animationNode->currentIteration());
+ EXPECT_EQ(0, animationNode->timeFraction());
+
+ animationNode->updateInheritedTime(std::numeric_limits<double>::infinity());
+
+ EXPECT_EQ(std::numeric_limits<double>::infinity(), animationNode->activeDurationInternal());
+ EXPECT_EQ(AnimationNode::PhaseAfter, animationNode->phase());
+ EXPECT_FALSE(animationNode->isInPlay());
+ EXPECT_FALSE(animationNode->isCurrent());
+ EXPECT_TRUE(animationNode->isInEffect());
+ EXPECT_EQ(0, animationNode->currentIteration());
+ EXPECT_EQ(0, animationNode->timeFraction());
+}
+
+TEST(AnimationAnimationNodeTest, EndTime)
+{
+ Timing timing;
+ timing.startDelay = 1;
+ timing.endDelay = 2;
+ timing.iterationDuration = 4;
+ timing.iterationCount = 2;
+ RefPtrWillBeRawPtr<TestAnimationNode> animationNode = TestAnimationNode::create(timing);
+ EXPECT_EQ(11, animationNode->endTimeInternal());
+}
+
+TEST(AnimationAnimationNodeTest, Events)
+{
+ Timing timing;
+ timing.iterationDuration = 1;
+ timing.fillMode = Timing::FillModeForwards;
+ timing.iterationCount = 2;
+ timing.startDelay = 1;
+ RefPtrWillBeRawPtr<TestAnimationNode> animationNode = TestAnimationNode::create(timing);
+
+ animationNode->updateInheritedTime(0.0, TimingUpdateOnDemand);
+ EXPECT_FALSE(animationNode->eventDelegate()->eventTriggered());
+
+ animationNode->updateInheritedTime(0.0, TimingUpdateForAnimationFrame);
+ EXPECT_TRUE(animationNode->eventDelegate()->eventTriggered());
+
+ animationNode->updateInheritedTime(1.5, TimingUpdateOnDemand);
+ EXPECT_FALSE(animationNode->eventDelegate()->eventTriggered());
+
+ animationNode->updateInheritedTime(1.5, TimingUpdateForAnimationFrame);
+ EXPECT_TRUE(animationNode->eventDelegate()->eventTriggered());
+
+}
+
+TEST(AnimationAnimationNodeTest, TimeToEffectChange)
+{
+ Timing timing;
+ timing.iterationDuration = 1;
+ timing.fillMode = Timing::FillModeForwards;
+ timing.iterationStart = 0.2;
+ timing.iterationCount = 2.5;
+ timing.startDelay = 1;
+ timing.direction = Timing::PlaybackDirectionAlternate;
+ RefPtrWillBeRawPtr<TestAnimationNode> animationNode = TestAnimationNode::create(timing);
+
+ animationNode->updateInheritedTime(0);
+ EXPECT_EQ(0, animationNode->takeLocalTime());
+ EXPECT_TRUE(std::isinf(animationNode->takeTimeToNextIteration()));
+
+ // Normal iteration.
+ animationNode->updateInheritedTime(1.75);
+ EXPECT_EQ(1.75, animationNode->takeLocalTime());
+ EXPECT_NEAR(0.05, animationNode->takeTimeToNextIteration(), 0.000000000000001);
+
+ // Reverse iteration.
+ animationNode->updateInheritedTime(2.75);
+ EXPECT_EQ(2.75, animationNode->takeLocalTime());
+ EXPECT_NEAR(0.05, animationNode->takeTimeToNextIteration(), 0.000000000000001);
+
+ // Item ends before iteration finishes.
+ animationNode->updateInheritedTime(3.4);
+ EXPECT_EQ(AnimationNode::PhaseActive, animationNode->phase());
+ EXPECT_EQ(3.4, animationNode->takeLocalTime());
+ EXPECT_TRUE(std::isinf(animationNode->takeTimeToNextIteration()));
+
+ // Item has finished.
+ animationNode->updateInheritedTime(3.5);
+ EXPECT_EQ(AnimationNode::PhaseAfter, animationNode->phase());
+ EXPECT_EQ(3.5, animationNode->takeLocalTime());
+ EXPECT_TRUE(std::isinf(animationNode->takeTimeToNextIteration()));
+}
+
+}
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimationNodeTiming.cpp b/chromium/third_party/WebKit/Source/core/animation/AnimationNodeTiming.cpp
new file mode 100644
index 00000000000..9c3ade81ab5
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimationNodeTiming.cpp
@@ -0,0 +1,180 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "config.h"
+#include "core/animation/AnimationNodeTiming.h"
+
+#include "core/animation/Animation.h"
+#include "core/animation/AnimationNode.h"
+#include "platform/animation/TimingFunction.h"
+
+namespace WebCore {
+
+PassRefPtrWillBeRawPtr<AnimationNodeTiming> AnimationNodeTiming::create(AnimationNode* parent)
+{
+ return adoptRefWillBeNoop(new AnimationNodeTiming(parent));
+}
+
+AnimationNodeTiming::AnimationNodeTiming(AnimationNode* parent)
+: m_parent(parent)
+{
+}
+
+double AnimationNodeTiming::delay()
+{
+ return m_parent->specifiedTiming().startDelay * 1000;
+}
+
+double AnimationNodeTiming::endDelay()
+{
+ return m_parent->specifiedTiming().endDelay * 1000;
+}
+
+String AnimationNodeTiming::fill()
+{
+ Timing::FillMode fillMode = m_parent->specifiedTiming().fillMode;
+ switch (fillMode) {
+ case Timing::FillModeNone:
+ return "none";
+ case Timing::FillModeForwards:
+ return "forwards";
+ case Timing::FillModeBackwards:
+ return "backwards";
+ case Timing::FillModeBoth:
+ return "both";
+ case Timing::FillModeAuto:
+ return "auto";
+ }
+ ASSERT_NOT_REACHED();
+ return "auto";
+}
+
+double AnimationNodeTiming::iterationStart()
+{
+ return m_parent->specifiedTiming().iterationStart;
+}
+
+double AnimationNodeTiming::iterations()
+{
+ return m_parent->specifiedTiming().iterationCount;
+}
+
+// This logic was copied from the example in bindings/tests/idls/TestInterface.idl
+// and bindings/tests/results/V8TestInterface.cpp.
+// FIXME: It might be possible to have 'duration' defined as an attribute in the idl.
+// If possible, fix will be in a follow-up patch.
+void AnimationNodeTiming::getDuration(String propertyName, bool& element0Enabled, double& element0, bool& element1Enabled, String& element1)
+{
+ if (propertyName != "duration")
+ return;
+
+ if (std::isnan(m_parent->specifiedTiming().iterationDuration)) {
+ element1Enabled = true;
+ element1 = "auto";
+ return;
+ }
+ element0Enabled = true;
+ element0 = m_parent->specifiedTiming().iterationDuration * 1000;
+ return;
+}
+
+double AnimationNodeTiming::playbackRate()
+{
+ return m_parent->specifiedTiming().playbackRate;
+}
+
+String AnimationNodeTiming::direction()
+{
+ Timing::PlaybackDirection direction = m_parent->specifiedTiming().direction;
+ switch (direction) {
+ case Timing::PlaybackDirectionNormal:
+ return "normal";
+ case Timing::PlaybackDirectionReverse:
+ return "reverse";
+ case Timing::PlaybackDirectionAlternate:
+ return "alternate";
+ case Timing::PlaybackDirectionAlternateReverse:
+ return "alternate-reverse";
+ }
+ ASSERT_NOT_REACHED();
+ return "normal";
+}
+
+String AnimationNodeTiming::easing()
+{
+ return m_parent->specifiedTiming().timingFunction->toString();
+}
+
+void AnimationNodeTiming::setDelay(double delay)
+{
+ Timing timing = m_parent->specifiedTiming();
+ TimingInput::setStartDelay(timing, delay);
+ m_parent->updateSpecifiedTiming(timing);
+}
+
+void AnimationNodeTiming::setEndDelay(double endDelay)
+{
+ Timing timing = m_parent->specifiedTiming();
+ TimingInput::setEndDelay(timing, endDelay);
+ m_parent->updateSpecifiedTiming(timing);
+}
+
+void AnimationNodeTiming::setFill(String fill)
+{
+ Timing timing = m_parent->specifiedTiming();
+ TimingInput::setFillMode(timing, fill);
+ m_parent->updateSpecifiedTiming(timing);
+}
+
+void AnimationNodeTiming::setIterationStart(double iterationStart)
+{
+ Timing timing = m_parent->specifiedTiming();
+ TimingInput::setIterationStart(timing, iterationStart);
+ m_parent->updateSpecifiedTiming(timing);
+}
+
+void AnimationNodeTiming::setIterations(double iterations)
+{
+ Timing timing = m_parent->specifiedTiming();
+ TimingInput::setIterationCount(timing, iterations);
+ m_parent->updateSpecifiedTiming(timing);
+}
+
+bool AnimationNodeTiming::setDuration(String name, double duration)
+{
+ if (name != "duration")
+ return false;
+ Timing timing = m_parent->specifiedTiming();
+ TimingInput::setIterationDuration(timing, duration);
+ m_parent->updateSpecifiedTiming(timing);
+ return true;
+}
+
+void AnimationNodeTiming::setPlaybackRate(double playbackRate)
+{
+ Timing timing = m_parent->specifiedTiming();
+ TimingInput::setPlaybackRate(timing, playbackRate);
+ m_parent->updateSpecifiedTiming(timing);
+}
+
+void AnimationNodeTiming::setDirection(String direction)
+{
+ Timing timing = m_parent->specifiedTiming();
+ TimingInput::setPlaybackDirection(timing, direction);
+ m_parent->updateSpecifiedTiming(timing);
+}
+
+void AnimationNodeTiming::setEasing(String easing)
+{
+ Timing timing = m_parent->specifiedTiming();
+ TimingInput::setTimingFunction(timing, easing);
+ m_parent->updateSpecifiedTiming(timing);
+}
+
+void AnimationNodeTiming::trace(Visitor* visitor)
+{
+ visitor->trace(m_parent);
+}
+
+} // namespace WebCore
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimationNodeTiming.h b/chromium/third_party/WebKit/Source/core/animation/AnimationNodeTiming.h
new file mode 100644
index 00000000000..c6570ec501f
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimationNodeTiming.h
@@ -0,0 +1,46 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef AnimationNodeTiming_h
+#define AnimationNodeTiming_h
+
+#include "core/animation/AnimationNode.h"
+#include "wtf/RefCounted.h"
+#include "wtf/text/WTFString.h"
+
+namespace WebCore {
+
+class AnimationNodeTiming : public RefCountedWillBeGarbageCollectedFinalized<AnimationNodeTiming> {
+public:
+ static PassRefPtrWillBeRawPtr<AnimationNodeTiming> create(AnimationNode* parent);
+ double delay();
+ double endDelay();
+ String fill();
+ double iterationStart();
+ double iterations();
+ void getDuration(String propertyName, bool& element0Enabled, double& element0, bool& element1Enabled, String& element1);
+ double playbackRate();
+ String direction();
+ String easing();
+
+ void setDelay(double);
+ void setEndDelay(double);
+ void setFill(String);
+ void setIterationStart(double);
+ void setIterations(double);
+ bool setDuration(String name, double duration);
+ void setPlaybackRate(double);
+ void setDirection(String);
+ void setEasing(String);
+
+ void trace(Visitor*);
+
+private:
+ RefPtrWillBeMember<AnimationNode> m_parent;
+ explicit AnimationNodeTiming(AnimationNode*);
+};
+
+} // namespace WebCore
+
+#endif
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimationPlayer.cpp b/chromium/third_party/WebKit/Source/core/animation/AnimationPlayer.cpp
new file mode 100644
index 00000000000..a99fec82f98
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimationPlayer.cpp
@@ -0,0 +1,460 @@
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "core/animation/AnimationPlayer.h"
+
+#include "core/animation/Animation.h"
+#include "core/animation/AnimationTimeline.h"
+#include "core/dom/Document.h"
+#include "core/events/AnimationPlayerEvent.h"
+#include "core/frame/UseCounter.h"
+
+namespace WebCore {
+
+namespace {
+
+static unsigned nextSequenceNumber()
+{
+ static unsigned next = 0;
+ return ++next;
+}
+
+}
+
+PassRefPtrWillBeRawPtr<AnimationPlayer> AnimationPlayer::create(ExecutionContext* executionContext, AnimationTimeline& timeline, AnimationNode* content)
+{
+ RefPtrWillBeRawPtr<AnimationPlayer> player = adoptRefWillBeRefCountedGarbageCollected(new AnimationPlayer(executionContext, timeline, content));
+ player->suspendIfNeeded();
+ return player.release();
+}
+
+AnimationPlayer::AnimationPlayer(ExecutionContext* executionContext, AnimationTimeline& timeline, AnimationNode* content)
+ : ActiveDOMObject(executionContext)
+ , m_playbackRate(1)
+ , m_startTime(nullValue())
+ , m_holdTime(nullValue())
+ , m_storedTimeLag(0)
+ , m_sortInfo(nextSequenceNumber(), timeline.effectiveTime())
+ , m_content(content)
+ , m_timeline(&timeline)
+ , m_paused(false)
+ , m_held(false)
+ , m_isPausedForTesting(false)
+ , m_outdated(true)
+ , m_finished(false)
+{
+ if (m_content) {
+ if (m_content->player())
+ m_content->player()->cancel();
+ m_content->attach(this);
+ }
+}
+
+AnimationPlayer::~AnimationPlayer()
+{
+#if !ENABLE(OILPAN)
+ if (m_content)
+ m_content->detach();
+ if (m_timeline)
+ m_timeline->playerDestroyed(this);
+#endif
+}
+
+double AnimationPlayer::sourceEnd() const
+{
+ return m_content ? m_content->endTimeInternal() : 0;
+}
+
+bool AnimationPlayer::limited(double currentTime) const
+{
+ return (m_playbackRate < 0 && currentTime <= 0) || (m_playbackRate > 0 && currentTime >= sourceEnd());
+}
+
+double AnimationPlayer::currentTimeWithoutLag() const
+{
+ if (isNull(m_startTime) || !m_timeline)
+ return 0;
+ return (m_timeline->effectiveTime() - m_startTime) * m_playbackRate;
+}
+
+double AnimationPlayer::currentTimeWithLag() const
+{
+ ASSERT(!m_held);
+ double time = currentTimeWithoutLag();
+ return std::isinf(time) ? time : time - m_storedTimeLag;
+}
+
+void AnimationPlayer::updateTimingState(double newCurrentTime)
+{
+ ASSERT(!isNull(newCurrentTime));
+ bool oldHeld = m_held;
+ m_held = m_paused || !m_playbackRate || limited(newCurrentTime);
+ if (m_held) {
+ if (!oldHeld || m_holdTime != newCurrentTime)
+ setOutdated();
+ m_holdTime = newCurrentTime;
+ m_storedTimeLag = nullValue();
+ } else {
+ m_holdTime = nullValue();
+ m_storedTimeLag = currentTimeWithoutLag() - newCurrentTime;
+ m_finished = false;
+ setOutdated();
+ }
+}
+
+void AnimationPlayer::updateCurrentTimingState()
+{
+ if (m_held) {
+ updateTimingState(m_holdTime);
+ return;
+ }
+ if (!limited(currentTimeWithLag()))
+ return;
+ m_held = true;
+ m_holdTime = m_playbackRate < 0 ? 0 : sourceEnd();
+ m_storedTimeLag = nullValue();
+}
+
+double AnimationPlayer::currentTime()
+{
+ return currentTimeInternal() * 1000;
+}
+
+double AnimationPlayer::currentTimeInternal()
+{
+ updateCurrentTimingState();
+ if (m_held)
+ return m_holdTime;
+ return currentTimeWithLag();
+}
+
+void AnimationPlayer::setCurrentTime(double newCurrentTime)
+{
+ setCurrentTimeInternal(newCurrentTime / 1000);
+}
+
+void AnimationPlayer::setCurrentTimeInternal(double newCurrentTime)
+{
+ if (!std::isfinite(newCurrentTime))
+ return;
+ updateTimingState(newCurrentTime);
+ cancelAnimationOnCompositor();
+ schedulePendingAnimationOnCompositor();
+}
+
+void AnimationPlayer::setStartTimeInternal(double newStartTime, bool isUpdateFromCompositor)
+{
+ ASSERT(!isUpdateFromCompositor || !hasStartTime());
+
+ if (!std::isfinite(newStartTime))
+ return;
+ if (newStartTime == m_startTime)
+ return;
+ updateCurrentTimingState(); // Update the value of held
+ bool hadStartTime = hasStartTime();
+ double previousCurrentTime = currentTimeInternal();
+ m_startTime = newStartTime;
+ m_sortInfo.m_startTime = newStartTime;
+ updateCurrentTimingState();
+ if (previousCurrentTime != currentTimeInternal()) {
+ setOutdated();
+ } else if (!hadStartTime && m_timeline) {
+ // Even though this player is not outdated, time to effect change is
+ // infinity until start time is set.
+ m_timeline->wake();
+ }
+ if (!isUpdateFromCompositor) {
+ cancelAnimationOnCompositor();
+ schedulePendingAnimationOnCompositor();
+ }
+}
+
+void AnimationPlayer::setSource(AnimationNode* newSource)
+{
+ if (m_content == newSource)
+ return;
+ cancelAnimationOnCompositor();
+ double storedCurrentTime = currentTimeInternal();
+ if (m_content)
+ m_content->detach();
+ m_content = newSource;
+ if (newSource) {
+ // FIXME: This logic needs to be updated once groups are implemented
+ if (newSource->player())
+ newSource->player()->cancel();
+ newSource->attach(this);
+ }
+ updateTimingState(storedCurrentTime);
+ schedulePendingAnimationOnCompositor();
+}
+
+void AnimationPlayer::pause()
+{
+ if (m_paused)
+ return;
+ m_paused = true;
+ updateTimingState(currentTimeInternal());
+ cancelAnimationOnCompositor();
+}
+
+void AnimationPlayer::unpause()
+{
+ if (!m_paused)
+ return;
+ m_paused = false;
+ updateTimingState(currentTimeInternal());
+ schedulePendingAnimationOnCompositor();
+}
+
+void AnimationPlayer::play()
+{
+ cancelAnimationOnCompositor();
+ // Note, unpause schedules pending animation on compositor if necessary.
+ unpause();
+ if (!m_content)
+ return;
+ double currentTime = this->currentTimeInternal();
+ if (m_playbackRate > 0 && (currentTime < 0 || currentTime >= sourceEnd()))
+ setCurrentTimeInternal(0);
+ else if (m_playbackRate < 0 && (currentTime <= 0 || currentTime > sourceEnd()))
+ setCurrentTimeInternal(sourceEnd());
+ m_finished = false;
+}
+
+void AnimationPlayer::reverse()
+{
+ if (!m_playbackRate)
+ return;
+ if (m_content) {
+ if (m_playbackRate > 0 && currentTimeInternal() > sourceEnd())
+ setCurrentTimeInternal(sourceEnd());
+ else if (m_playbackRate < 0 && currentTimeInternal() < 0)
+ setCurrentTimeInternal(0);
+ }
+ setPlaybackRate(-m_playbackRate);
+ cancelAnimationOnCompositor();
+ // Note, unpause schedules pending animation on compositor if necessary.
+ unpause();
+}
+
+void AnimationPlayer::finish(ExceptionState& exceptionState)
+{
+ if (!m_playbackRate)
+ return;
+ if (m_playbackRate < 0) {
+ setCurrentTimeInternal(0);
+ } else {
+ if (sourceEnd() == std::numeric_limits<double>::infinity()) {
+ exceptionState.throwDOMException(InvalidStateError, "AnimationPlayer has source content whose end time is infinity.");
+ return;
+ }
+ setCurrentTimeInternal(sourceEnd());
+ }
+ ASSERT(finished());
+ cancelAnimationOnCompositor();
+}
+
+const AtomicString& AnimationPlayer::interfaceName() const
+{
+ return EventTargetNames::AnimationPlayer;
+}
+
+ExecutionContext* AnimationPlayer::executionContext() const
+{
+ return ActiveDOMObject::executionContext();
+}
+
+bool AnimationPlayer::hasPendingActivity() const
+{
+ return m_pendingFinishedEvent || (!m_finished && hasEventListeners(EventTypeNames::finish));
+}
+
+void AnimationPlayer::stop()
+{
+ m_finished = true;
+ m_pendingFinishedEvent = nullptr;
+}
+
+bool AnimationPlayer::dispatchEvent(PassRefPtrWillBeRawPtr<Event> event)
+{
+ if (m_pendingFinishedEvent == event)
+ m_pendingFinishedEvent = nullptr;
+ return EventTargetWithInlineData::dispatchEvent(event);
+}
+
+void AnimationPlayer::setPlaybackRate(double playbackRate)
+{
+ if (!std::isfinite(playbackRate))
+ return;
+ double storedCurrentTime = currentTimeInternal();
+ if ((m_playbackRate < 0 && playbackRate >= 0) || (m_playbackRate > 0 && playbackRate <= 0))
+ m_finished = false;
+ m_playbackRate = playbackRate;
+ updateTimingState(storedCurrentTime);
+ cancelAnimationOnCompositor();
+ schedulePendingAnimationOnCompositor();
+}
+
+void AnimationPlayer::setOutdated()
+{
+ m_outdated = true;
+ if (m_timeline)
+ m_timeline->setOutdatedAnimationPlayer(this);
+}
+
+bool AnimationPlayer::canStartAnimationOnCompositor()
+{
+ // FIXME: Need compositor support for playback rate != 1.
+ if (playbackRate() != 1)
+ return false;
+
+ return m_timeline && m_content && m_content->isAnimation() && !m_held;
+}
+
+bool AnimationPlayer::maybeStartAnimationOnCompositor()
+{
+ if (!canStartAnimationOnCompositor())
+ return false;
+
+ return toAnimation(m_content.get())->maybeStartAnimationOnCompositor(timeline()->zeroTime() + startTimeInternal() + timeLagInternal());
+}
+
+void AnimationPlayer::schedulePendingAnimationOnCompositor()
+{
+ ASSERT(!hasActiveAnimationsOnCompositor());
+
+ if (canStartAnimationOnCompositor())
+ timeline()->document()->compositorPendingAnimations().add(this);
+}
+
+bool AnimationPlayer::hasActiveAnimationsOnCompositor()
+{
+ if (!m_content || !m_content->isAnimation())
+ return false;
+
+ return toAnimation(m_content.get())->hasActiveAnimationsOnCompositor();
+}
+
+void AnimationPlayer::cancelAnimationOnCompositor()
+{
+ if (hasActiveAnimationsOnCompositor())
+ toAnimation(m_content.get())->cancelAnimationOnCompositor();
+}
+
+bool AnimationPlayer::update(TimingUpdateReason reason)
+{
+ m_outdated = false;
+
+ if (!m_timeline)
+ return false;
+
+ if (m_content) {
+ double inheritedTime = isNull(m_timeline->currentTimeInternal()) ? nullValue() : currentTimeInternal();
+ m_content->updateInheritedTime(inheritedTime, reason);
+ }
+
+ if (finished() && !m_finished) {
+ if (reason == TimingUpdateForAnimationFrame && hasStartTime()) {
+ const AtomicString& eventType = EventTypeNames::finish;
+ if (executionContext() && hasEventListeners(eventType)) {
+ m_pendingFinishedEvent = AnimationPlayerEvent::create(eventType, currentTime(), timeline()->currentTime());
+ m_pendingFinishedEvent->setTarget(this);
+ m_pendingFinishedEvent->setCurrentTarget(this);
+ m_timeline->document()->enqueueAnimationFrameEvent(m_pendingFinishedEvent);
+ }
+ m_finished = true;
+ }
+ }
+ ASSERT(!m_outdated);
+ return !m_finished || !finished();
+}
+
+double AnimationPlayer::timeToEffectChange()
+{
+ ASSERT(!m_outdated);
+ if (m_held || !hasStartTime())
+ return std::numeric_limits<double>::infinity();
+ if (!m_content)
+ return -currentTimeInternal() / m_playbackRate;
+ if (m_playbackRate > 0)
+ return m_content->timeToForwardsEffectChange() / m_playbackRate;
+ return m_content->timeToReverseEffectChange() / -m_playbackRate;
+}
+
+void AnimationPlayer::cancel()
+{
+ setSource(0);
+}
+
+bool AnimationPlayer::SortInfo::operator<(const SortInfo& other) const
+{
+ ASSERT(!std::isnan(m_startTime) && !std::isnan(other.m_startTime));
+ if (m_startTime < other.m_startTime)
+ return true;
+ if (m_startTime > other.m_startTime)
+ return false;
+ return m_sequenceNumber < other.m_sequenceNumber;
+}
+
+#if !ENABLE(OILPAN)
+bool AnimationPlayer::canFree() const
+{
+ ASSERT(m_content);
+ return hasOneRef() && m_content->isAnimation() && m_content->hasOneRef();
+}
+#endif
+
+bool AnimationPlayer::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener, bool useCapture)
+{
+ if (eventType == EventTypeNames::finish)
+ UseCounter::count(executionContext(), UseCounter::AnimationPlayerFinishEvent);
+ return EventTargetWithInlineData::addEventListener(eventType, listener, useCapture);
+}
+
+void AnimationPlayer::pauseForTesting(double pauseTime)
+{
+ RELEASE_ASSERT(!paused());
+ updateTimingState(pauseTime);
+ if (!m_isPausedForTesting && hasActiveAnimationsOnCompositor())
+ toAnimation(m_content.get())->pauseAnimationForTestingOnCompositor(currentTimeInternal());
+ m_isPausedForTesting = true;
+ pause();
+}
+
+void AnimationPlayer::trace(Visitor* visitor)
+{
+ visitor->trace(m_content);
+ visitor->trace(m_timeline);
+ visitor->trace(m_pendingFinishedEvent);
+ EventTargetWithInlineData::trace(visitor);
+}
+
+} // namespace
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimationPlayer.h b/chromium/third_party/WebKit/Source/core/animation/AnimationPlayer.h
new file mode 100644
index 00000000000..e0c44eb72a9
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimationPlayer.h
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef AnimationPlayer_h
+#define AnimationPlayer_h
+
+#include "core/animation/AnimationNode.h"
+#include "core/dom/ActiveDOMObject.h"
+#include "core/events/EventTarget.h"
+#include "wtf/RefPtr.h"
+
+namespace WebCore {
+
+class AnimationTimeline;
+class ExceptionState;
+
+class AnimationPlayer FINAL : public RefCountedWillBeRefCountedGarbageCollected<AnimationPlayer>
+ , public ActiveDOMObject
+ , public EventTargetWithInlineData {
+ REFCOUNTED_EVENT_TARGET(AnimationPlayer);
+ WILL_BE_USING_GARBAGE_COLLECTED_MIXIN(AnimationPlayer);
+public:
+
+ ~AnimationPlayer();
+ static PassRefPtrWillBeRawPtr<AnimationPlayer> create(ExecutionContext*, AnimationTimeline&, AnimationNode*);
+
+ // Returns whether the player is finished.
+ bool update(TimingUpdateReason);
+
+ // timeToEffectChange returns:
+ // infinity - if this player is no longer in effect
+ // 0 - if this player requires an update on the next frame
+ // n - if this player requires an update after 'n' units of time
+ double timeToEffectChange();
+
+ void cancel();
+
+ double currentTime();
+ void setCurrentTime(double newCurrentTime);
+
+ double currentTimeInternal();
+ void setCurrentTimeInternal(double newCurrentTime);
+
+ bool paused() const { return m_paused && !m_isPausedForTesting; }
+ void pause();
+ void play();
+ void reverse();
+ void finish(ExceptionState&);
+ bool finished() { return limited(currentTimeInternal()); }
+ // FIXME: Resolve whether finished() should just return the flag, and
+ // remove this method.
+ bool finishedInternal() const { return m_finished; }
+
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(finish);
+
+ virtual const AtomicString& interfaceName() const OVERRIDE;
+ virtual ExecutionContext* executionContext() const OVERRIDE;
+ virtual bool hasPendingActivity() const OVERRIDE;
+ virtual void stop() OVERRIDE;
+ virtual bool dispatchEvent(PassRefPtrWillBeRawPtr<Event>) OVERRIDE;
+
+ double playbackRate() const { return m_playbackRate; }
+ void setPlaybackRate(double);
+ const AnimationTimeline* timeline() const { return m_timeline; }
+ AnimationTimeline* timeline() { return m_timeline; }
+
+#if !ENABLE(OILPAN)
+ void timelineDestroyed() { m_timeline = nullptr; }
+#endif
+
+ bool hasStartTime() const { return !isNull(m_startTime); }
+ double startTime() const { return m_startTime * 1000; }
+ double startTimeInternal() const { return m_startTime; }
+ void setStartTime(double startTime) { setStartTimeInternal(startTime / 1000); }
+ void setStartTimeInternal(double, bool isUpdateFromCompositor = false);
+
+ const AnimationNode* source() const { return m_content.get(); }
+ AnimationNode* source() { return m_content.get(); }
+ AnimationNode* source(bool& isNull) { isNull = !m_content; return m_content.get(); }
+ void setSource(AnimationNode*);
+
+ double timeLag() { return timeLagInternal() * 1000; }
+ double timeLagInternal() { return currentTimeWithoutLag() - currentTimeInternal(); }
+
+ // Pausing via this method is not reflected in the value returned by
+ // paused() and must never overlap with pausing via pause().
+ void pauseForTesting(double pauseTime);
+ // This should only be used for CSS
+ void unpause();
+
+ void setOutdated();
+ bool outdated() { return m_outdated; }
+
+ bool canStartAnimationOnCompositor();
+ bool maybeStartAnimationOnCompositor();
+ void cancelAnimationOnCompositor();
+ void schedulePendingAnimationOnCompositor();
+ bool hasActiveAnimationsOnCompositor();
+
+ class SortInfo {
+ public:
+ friend class AnimationPlayer;
+ bool operator<(const SortInfo& other) const;
+ double startTime() const { return m_startTime; }
+ private:
+ SortInfo(unsigned sequenceNumber, double startTime)
+ : m_sequenceNumber(sequenceNumber)
+ , m_startTime(startTime)
+ {
+ }
+ unsigned m_sequenceNumber;
+ double m_startTime;
+ };
+
+ const SortInfo& sortInfo() const { return m_sortInfo; }
+
+ static bool hasLowerPriority(AnimationPlayer* player1, AnimationPlayer* player2)
+ {
+ return player1->sortInfo() < player2->sortInfo();
+ }
+
+#if !ENABLE(OILPAN)
+ // Checks if the AnimationStack is the last reference holder to the Player.
+ // This won't be needed when AnimationPlayer is moved to Oilpan.
+ bool canFree() const;
+#endif
+
+ virtual bool addEventListener(const AtomicString& eventType, PassRefPtr<EventListener>, bool useCapture = false) OVERRIDE;
+
+ virtual void trace(Visitor*) OVERRIDE;
+
+private:
+ AnimationPlayer(ExecutionContext*, AnimationTimeline&, AnimationNode*);
+ double sourceEnd() const;
+ bool limited(double currentTime) const;
+ double currentTimeWithoutLag() const;
+ double currentTimeWithLag() const;
+ void updateTimingState(double newCurrentTime);
+ void updateCurrentTimingState();
+
+ double m_playbackRate;
+ double m_startTime;
+ double m_holdTime;
+ double m_storedTimeLag;
+
+ SortInfo m_sortInfo;
+
+ RefPtrWillBeMember<AnimationNode> m_content;
+ RawPtrWillBeMember<AnimationTimeline> m_timeline;
+ // Reflects all pausing, including via pauseForTesting().
+ bool m_paused;
+ bool m_held;
+ bool m_isPausedForTesting;
+
+ // This indicates timing information relevant to the player has changed by
+ // means other than the ordinary progression of time
+ bool m_outdated;
+
+ bool m_finished;
+ // Holds a 'finished' event queued for asynchronous dispatch via the
+ // ScriptedAnimationController. This object remains active until the
+ // event is actually dispatched.
+ RefPtrWillBeMember<Event> m_pendingFinishedEvent;
+};
+
+} // namespace
+
+#endif
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimationPlayer.idl b/chromium/third_party/WebKit/Source/core/animation/AnimationPlayer.idl
new file mode 100644
index 00000000000..8dc0d416d6a
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimationPlayer.idl
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+[
+ RuntimeEnabled=WebAnimationsElementAnimate,
+ NoInterfaceObject,
+ WillBeGarbageCollected,
+ ActiveDOMObject,
+] interface AnimationPlayer : EventTarget {
+ [RuntimeEnabled=WebAnimationsAPI] attribute AnimationNode? source;
+ [RuntimeEnabled=WebAnimationsAPI] attribute double startTime;
+ [RuntimeEnabled=WebAnimationsAPI] attribute double currentTime;
+ [RuntimeEnabled=WebAnimationsAPI] readonly attribute double timeLag;
+ [RuntimeEnabled=WebAnimationsAPI] attribute double playbackRate;
+ [RuntimeEnabled=WebAnimationsAPI] readonly attribute boolean paused;
+ [RuntimeEnabled=WebAnimationsAPI] readonly attribute boolean finished;
+ [RuntimeEnabled=WebAnimationsAPI, RaisesException] void finish();
+ [RuntimeEnabled=WebAnimationsAPI] void play();
+ [RuntimeEnabled=WebAnimationsAPI] void pause();
+ [RuntimeEnabled=WebAnimationsAPI] void reverse();
+
+ void cancel();
+ [MeasureAs=AnimationPlayerFinishEvent] attribute EventHandler onfinish;
+};
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimationPlayerTest.cpp b/chromium/third_party/WebKit/Source/core/animation/AnimationPlayerTest.cpp
new file mode 100644
index 00000000000..37660e69b82
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimationPlayerTest.cpp
@@ -0,0 +1,737 @@
+/*
+ * Copyright (c) 2013, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "core/animation/AnimationPlayer.h"
+
+#include "core/animation/ActiveAnimations.h"
+#include "core/animation/Animation.h"
+#include "core/animation/AnimationClock.h"
+#include "core/animation/AnimationTimeline.h"
+#include "core/dom/Document.h"
+#include "core/dom/QualifiedName.h"
+#include "platform/weborigin/KURL.h"
+#include <gtest/gtest.h>
+
+using namespace WebCore;
+
+namespace {
+
+class AnimationAnimationPlayerTest : public ::testing::Test {
+protected:
+ virtual void SetUp()
+ {
+ setUpWithoutStartingTimeline();
+ startTimeline();
+ }
+
+ void setUpWithoutStartingTimeline()
+ {
+ document = Document::create();
+ document->animationClock().resetTimeForTesting();
+ timeline = AnimationTimeline::create(document.get());
+ player = timeline->createAnimationPlayer(0);
+ player->setStartTimeInternal(0);
+ player->setSource(makeAnimation().get());
+ }
+
+ void startTimeline()
+ {
+ updateTimeline(0);
+ }
+
+ PassRefPtrWillBeRawPtr<Animation> makeAnimation(double duration = 30, double playbackRate = 1)
+ {
+ Timing timing;
+ timing.iterationDuration = duration;
+ timing.playbackRate = playbackRate;
+ return Animation::create(0, nullptr, timing);
+ }
+
+ bool updateTimeline(double time)
+ {
+ document->animationClock().updateTime(time);
+ // The timeline does not know about our player, so we have to explicitly call update().
+ return player->update(TimingUpdateOnDemand);
+ }
+
+ RefPtrWillBePersistent<Document> document;
+ RefPtrWillBePersistent<AnimationTimeline> timeline;
+ RefPtrWillBePersistent<AnimationPlayer> player;
+ TrackExceptionState exceptionState;
+};
+
+TEST_F(AnimationAnimationPlayerTest, InitialState)
+{
+ setUpWithoutStartingTimeline();
+ player = timeline->createAnimationPlayer(0);
+ EXPECT_EQ(0, player->currentTimeInternal());
+ EXPECT_FALSE(player->paused());
+ EXPECT_EQ(1, player->playbackRate());
+ EXPECT_EQ(0, player->timeLagInternal());
+ EXPECT_FALSE(player->hasStartTime());
+ EXPECT_TRUE(isNull(player->startTimeInternal()));
+
+ startTimeline();
+ player->setStartTimeInternal(0);
+ EXPECT_EQ(0, timeline->currentTimeInternal());
+ EXPECT_EQ(0, player->currentTimeInternal());
+ EXPECT_FALSE(player->paused());
+ EXPECT_EQ(1, player->playbackRate());
+ EXPECT_EQ(0, player->startTimeInternal());
+ EXPECT_EQ(0, player->timeLagInternal());
+ EXPECT_TRUE(player->hasStartTime());
+}
+
+
+TEST_F(AnimationAnimationPlayerTest, CurrentTimeDoesNotSetOutdated)
+{
+ EXPECT_FALSE(player->outdated());
+ EXPECT_EQ(0, player->currentTimeInternal());
+ EXPECT_FALSE(player->outdated());
+ // FIXME: We should split updateTimeline into a version that doesn't update
+ // the player and one that does, as most of the tests don't require update()
+ // to be called.
+ document->animationClock().updateTime(10);
+ EXPECT_EQ(10, player->currentTimeInternal());
+ EXPECT_FALSE(player->outdated());
+}
+
+TEST_F(AnimationAnimationPlayerTest, SetCurrentTime)
+{
+ player->setCurrentTimeInternal(10);
+ EXPECT_EQ(10, player->currentTimeInternal());
+ updateTimeline(10);
+ EXPECT_EQ(20, player->currentTimeInternal());
+}
+
+TEST_F(AnimationAnimationPlayerTest, SetCurrentTimeNegative)
+{
+ player->setCurrentTimeInternal(-10);
+ EXPECT_EQ(-10, player->currentTimeInternal());
+ updateTimeline(20);
+ EXPECT_EQ(10, player->currentTimeInternal());
+
+ player->setPlaybackRate(-2);
+ player->setCurrentTimeInternal(-10);
+ EXPECT_EQ(-10, player->currentTimeInternal());
+ updateTimeline(40);
+ EXPECT_EQ(-10, player->currentTimeInternal());
+}
+
+TEST_F(AnimationAnimationPlayerTest, SetCurrentTimePastContentEnd)
+{
+ player->setCurrentTimeInternal(50);
+ EXPECT_EQ(50, player->currentTimeInternal());
+ updateTimeline(20);
+ EXPECT_EQ(50, player->currentTimeInternal());
+
+ player->setPlaybackRate(-2);
+ player->setCurrentTimeInternal(50);
+ EXPECT_EQ(50, player->currentTimeInternal());
+ updateTimeline(40);
+ EXPECT_EQ(10, player->currentTimeInternal());
+}
+
+TEST_F(AnimationAnimationPlayerTest, SetCurrentTimeBeforeTimelineStarted)
+{
+ setUpWithoutStartingTimeline();
+ player->setCurrentTimeInternal(5);
+ EXPECT_EQ(5, player->currentTimeInternal());
+ startTimeline();
+ updateTimeline(10);
+ EXPECT_EQ(15, player->currentTimeInternal());
+}
+
+TEST_F(AnimationAnimationPlayerTest, SetCurrentTimePastContentEndBeforeTimelineStarted)
+{
+ setUpWithoutStartingTimeline();
+ player->setCurrentTimeInternal(250);
+ EXPECT_EQ(250, player->currentTimeInternal());
+ startTimeline();
+ updateTimeline(10);
+ EXPECT_EQ(250, player->currentTimeInternal());
+}
+
+TEST_F(AnimationAnimationPlayerTest, SetCurrentTimeMax)
+{
+ player->setCurrentTimeInternal(std::numeric_limits<double>::max());
+ EXPECT_EQ(std::numeric_limits<double>::max(), player->currentTimeInternal());
+ updateTimeline(100);
+ EXPECT_EQ(std::numeric_limits<double>::max(), player->currentTimeInternal());
+}
+
+TEST_F(AnimationAnimationPlayerTest, SetCurrentTimeUnrestrictedDouble)
+{
+ updateTimeline(10);
+ player->setCurrentTimeInternal(nullValue());
+ EXPECT_EQ(10, player->currentTimeInternal());
+ player->setCurrentTimeInternal(std::numeric_limits<double>::infinity());
+ EXPECT_EQ(10, player->currentTimeInternal());
+ player->setCurrentTimeInternal(-std::numeric_limits<double>::infinity());
+ EXPECT_EQ(10, player->currentTimeInternal());
+}
+
+TEST_F(AnimationAnimationPlayerTest, TimeLag)
+{
+ player->setCurrentTimeInternal(10);
+ EXPECT_EQ(-10, player->timeLagInternal());
+ updateTimeline(10);
+ EXPECT_EQ(-10, player->timeLagInternal());
+ player->setCurrentTimeInternal(40);
+ EXPECT_EQ(-30, player->timeLagInternal());
+ updateTimeline(20);
+ EXPECT_EQ(-20, player->timeLagInternal());
+}
+
+
+TEST_F(AnimationAnimationPlayerTest, SetStartTime)
+{
+ updateTimeline(20);
+ EXPECT_EQ(0, player->startTimeInternal());
+ EXPECT_EQ(20, player->currentTimeInternal());
+ player->setStartTimeInternal(10);
+ EXPECT_EQ(10, player->startTimeInternal());
+ EXPECT_EQ(10, player->currentTimeInternal());
+ updateTimeline(30);
+ EXPECT_EQ(10, player->startTimeInternal());
+ EXPECT_EQ(20, player->currentTimeInternal());
+}
+
+TEST_F(AnimationAnimationPlayerTest, SetStartTimeLimitsAnimationPlayer)
+{
+ player->setStartTimeInternal(-50);
+ EXPECT_EQ(30, player->currentTimeInternal());
+ player->setPlaybackRate(-1);
+ player->setStartTimeInternal(-100);
+ EXPECT_EQ(0, player->currentTimeInternal());
+ EXPECT_TRUE(player->finished());
+}
+
+TEST_F(AnimationAnimationPlayerTest, SetStartTimeOnLimitedAnimationPlayer)
+{
+ updateTimeline(30);
+ player->setStartTimeInternal(-10);
+ EXPECT_EQ(30, player->currentTimeInternal());
+ player->setCurrentTimeInternal(50);
+ player->setStartTimeInternal(-40);
+ EXPECT_EQ(50, player->currentTimeInternal());
+ EXPECT_TRUE(player->finished());
+}
+
+TEST_F(AnimationAnimationPlayerTest, SetStartTimeWhilePaused)
+{
+ updateTimeline(10);
+ player->pause();
+ player->setStartTimeInternal(-40);
+ EXPECT_EQ(10, player->currentTimeInternal());
+ updateTimeline(50);
+ player->setStartTimeInternal(60);
+ EXPECT_EQ(10, player->currentTimeInternal());
+}
+
+
+TEST_F(AnimationAnimationPlayerTest, PausePlay)
+{
+ updateTimeline(10);
+ player->pause();
+ EXPECT_TRUE(player->paused());
+ EXPECT_EQ(10, player->currentTimeInternal());
+ updateTimeline(20);
+ player->play();
+ EXPECT_FALSE(player->paused());
+ EXPECT_EQ(10, player->currentTimeInternal());
+ updateTimeline(30);
+ EXPECT_EQ(20, player->currentTimeInternal());
+}
+
+TEST_F(AnimationAnimationPlayerTest, PauseBeforeTimelineStarted)
+{
+ setUpWithoutStartingTimeline();
+ player->pause();
+ EXPECT_TRUE(player->paused());
+ player->play();
+ EXPECT_FALSE(player->paused());
+
+ player->pause();
+ startTimeline();
+ updateTimeline(100);
+ EXPECT_TRUE(player->paused());
+ EXPECT_EQ(0, player->currentTimeInternal());
+}
+
+TEST_F(AnimationAnimationPlayerTest, PauseBeforeStartTimeSet)
+{
+ player = timeline->createAnimationPlayer(makeAnimation().get());
+ updateTimeline(100);
+ player->pause();
+ updateTimeline(200);
+ EXPECT_EQ(0, player->currentTimeInternal());
+
+ player->setStartTimeInternal(150);
+ player->play();
+ EXPECT_EQ(0, player->currentTimeInternal());
+ updateTimeline(220);
+ EXPECT_EQ(20, player->currentTimeInternal());
+}
+
+TEST_F(AnimationAnimationPlayerTest, PlayRewindsToStart)
+{
+ player->setCurrentTimeInternal(30);
+ player->play();
+ EXPECT_EQ(0, player->currentTimeInternal());
+
+ player->setCurrentTimeInternal(40);
+ player->play();
+ EXPECT_EQ(0, player->currentTimeInternal());
+
+ player->setCurrentTimeInternal(-10);
+ player->play();
+ EXPECT_EQ(0, player->currentTimeInternal());
+}
+
+TEST_F(AnimationAnimationPlayerTest, PlayRewindsToEnd)
+{
+ player->setPlaybackRate(-1);
+ player->play();
+ EXPECT_EQ(30, player->currentTimeInternal());
+
+ player->setCurrentTimeInternal(40);
+ player->play();
+ EXPECT_EQ(30, player->currentTimeInternal());
+
+ player->setCurrentTimeInternal(-10);
+ player->play();
+ EXPECT_EQ(30, player->currentTimeInternal());
+}
+
+TEST_F(AnimationAnimationPlayerTest, PlayWithPlaybackRateZeroDoesNotSeek)
+{
+ player->setPlaybackRate(0);
+ player->play();
+ EXPECT_EQ(0, player->currentTimeInternal());
+
+ player->setCurrentTimeInternal(40);
+ player->play();
+ EXPECT_EQ(40, player->currentTimeInternal());
+
+ player->setCurrentTimeInternal(-10);
+ player->play();
+ EXPECT_EQ(-10, player->currentTimeInternal());
+}
+
+
+TEST_F(AnimationAnimationPlayerTest, Reverse)
+{
+ player->setCurrentTimeInternal(10);
+ player->pause();
+ player->reverse();
+ EXPECT_FALSE(player->paused());
+ EXPECT_EQ(-1, player->playbackRate());
+ EXPECT_EQ(10, player->currentTimeInternal());
+}
+
+TEST_F(AnimationAnimationPlayerTest, ReverseDoesNothingWithPlaybackRateZero)
+{
+ player->setCurrentTimeInternal(10);
+ player->setPlaybackRate(0);
+ player->pause();
+ player->reverse();
+ EXPECT_TRUE(player->paused());
+ EXPECT_EQ(0, player->playbackRate());
+ EXPECT_EQ(10, player->currentTimeInternal());
+}
+
+TEST_F(AnimationAnimationPlayerTest, ReverseDoesNotSeekWithNoSource)
+{
+ player->setSource(0);
+ player->setCurrentTimeInternal(10);
+ player->reverse();
+ EXPECT_EQ(10, player->currentTimeInternal());
+}
+
+TEST_F(AnimationAnimationPlayerTest, ReverseSeeksToStart)
+{
+ player->setCurrentTimeInternal(-10);
+ player->setPlaybackRate(-1);
+ player->reverse();
+ EXPECT_EQ(0, player->currentTimeInternal());
+}
+
+TEST_F(AnimationAnimationPlayerTest, ReverseSeeksToEnd)
+{
+ player->setCurrentTimeInternal(40);
+ player->reverse();
+ EXPECT_EQ(30, player->currentTimeInternal());
+}
+
+TEST_F(AnimationAnimationPlayerTest, ReverseLimitsAnimationPlayer)
+{
+ player->setCurrentTimeInternal(40);
+ player->setPlaybackRate(-1);
+ player->reverse();
+ EXPECT_TRUE(player->finished());
+ EXPECT_EQ(40, player->currentTimeInternal());
+
+ player->setCurrentTimeInternal(-10);
+ player->reverse();
+ EXPECT_TRUE(player->finished());
+ EXPECT_EQ(-10, player->currentTimeInternal());
+}
+
+
+TEST_F(AnimationAnimationPlayerTest, Finish)
+{
+ player->finish(exceptionState);
+ EXPECT_EQ(30, player->currentTimeInternal());
+ EXPECT_TRUE(player->finished());
+
+ player->setPlaybackRate(-1);
+ player->finish(exceptionState);
+ EXPECT_EQ(0, player->currentTimeInternal());
+ EXPECT_TRUE(player->finished());
+
+ EXPECT_FALSE(exceptionState.hadException());
+}
+
+TEST_F(AnimationAnimationPlayerTest, FinishAfterSourceEnd)
+{
+ player->setCurrentTimeInternal(40);
+ player->finish(exceptionState);
+ EXPECT_EQ(30, player->currentTimeInternal());
+}
+
+TEST_F(AnimationAnimationPlayerTest, FinishBeforeStart)
+{
+ player->setCurrentTimeInternal(-10);
+ player->setPlaybackRate(-1);
+ player->finish(exceptionState);
+ EXPECT_EQ(0, player->currentTimeInternal());
+}
+
+TEST_F(AnimationAnimationPlayerTest, FinishDoesNothingWithPlaybackRateZero)
+{
+ player->setCurrentTimeInternal(10);
+ player->setPlaybackRate(0);
+ player->finish(exceptionState);
+ EXPECT_EQ(10, player->currentTimeInternal());
+}
+
+TEST_F(AnimationAnimationPlayerTest, FinishRaisesException)
+{
+ Timing timing;
+ timing.iterationDuration = 1;
+ timing.iterationCount = std::numeric_limits<double>::infinity();
+ player->setSource(Animation::create(0, nullptr, timing).get());
+ player->setCurrentTimeInternal(10);
+
+ player->finish(exceptionState);
+ EXPECT_EQ(10, player->currentTimeInternal());
+ EXPECT_TRUE(exceptionState.hadException());
+ EXPECT_EQ(InvalidStateError, exceptionState.code());
+}
+
+
+TEST_F(AnimationAnimationPlayerTest, LimitingAtSourceEnd)
+{
+ updateTimeline(30);
+ EXPECT_EQ(30, player->currentTimeInternal());
+ EXPECT_TRUE(player->finished());
+ updateTimeline(40);
+ EXPECT_EQ(30, player->currentTimeInternal());
+ EXPECT_FALSE(player->paused());
+}
+
+TEST_F(AnimationAnimationPlayerTest, LimitingAtStart)
+{
+ updateTimeline(30);
+ player->setPlaybackRate(-2);
+ updateTimeline(45);
+ EXPECT_EQ(0, player->currentTimeInternal());
+ EXPECT_TRUE(player->finished());
+ updateTimeline(60);
+ EXPECT_EQ(0, player->currentTimeInternal());
+ EXPECT_FALSE(player->paused());
+}
+
+TEST_F(AnimationAnimationPlayerTest, LimitingWithNoSource)
+{
+ player->setSource(0);
+ EXPECT_TRUE(player->finished());
+ updateTimeline(30);
+ EXPECT_EQ(0, player->currentTimeInternal());
+}
+
+
+TEST_F(AnimationAnimationPlayerTest, SetPlaybackRate)
+{
+ player->setPlaybackRate(2);
+ EXPECT_EQ(2, player->playbackRate());
+ EXPECT_EQ(0, player->currentTimeInternal());
+ updateTimeline(10);
+ EXPECT_EQ(20, player->currentTimeInternal());
+}
+
+TEST_F(AnimationAnimationPlayerTest, SetPlaybackRateBeforeTimelineStarted)
+{
+ setUpWithoutStartingTimeline();
+ player->setPlaybackRate(2);
+ EXPECT_EQ(2, player->playbackRate());
+ EXPECT_EQ(0, player->currentTimeInternal());
+ startTimeline();
+ updateTimeline(10);
+ EXPECT_EQ(20, player->currentTimeInternal());
+}
+
+TEST_F(AnimationAnimationPlayerTest, SetPlaybackRateWhilePaused)
+{
+ updateTimeline(10);
+ player->pause();
+ player->setPlaybackRate(2);
+ updateTimeline(20);
+ player->play();
+ EXPECT_EQ(10, player->currentTimeInternal());
+ updateTimeline(25);
+ EXPECT_EQ(20, player->currentTimeInternal());
+}
+
+TEST_F(AnimationAnimationPlayerTest, SetPlaybackRateWhileLimited)
+{
+ updateTimeline(40);
+ EXPECT_EQ(30, player->currentTimeInternal());
+ player->setPlaybackRate(2);
+ updateTimeline(50);
+ EXPECT_EQ(30, player->currentTimeInternal());
+ player->setPlaybackRate(-2);
+ EXPECT_FALSE(player->finished());
+ updateTimeline(60);
+ EXPECT_EQ(10, player->currentTimeInternal());
+}
+
+TEST_F(AnimationAnimationPlayerTest, SetPlaybackRateZero)
+{
+ updateTimeline(10);
+ player->setPlaybackRate(0);
+ EXPECT_EQ(10, player->currentTimeInternal());
+ updateTimeline(20);
+ EXPECT_EQ(10, player->currentTimeInternal());
+ player->setCurrentTimeInternal(20);
+ EXPECT_EQ(20, player->currentTimeInternal());
+}
+
+TEST_F(AnimationAnimationPlayerTest, SetPlaybackRateMax)
+{
+ player->setPlaybackRate(std::numeric_limits<double>::max());
+ EXPECT_EQ(std::numeric_limits<double>::max(), player->playbackRate());
+ EXPECT_EQ(0, player->currentTimeInternal());
+ updateTimeline(1);
+ EXPECT_EQ(30, player->currentTimeInternal());
+}
+
+
+TEST_F(AnimationAnimationPlayerTest, SetSource)
+{
+ player = timeline->createAnimationPlayer(0);
+ player->setStartTimeInternal(0);
+ RefPtrWillBeRawPtr<AnimationNode> source1 = makeAnimation();
+ RefPtrWillBeRawPtr<AnimationNode> source2 = makeAnimation();
+ player->setSource(source1.get());
+ EXPECT_EQ(source1, player->source());
+ EXPECT_EQ(0, player->currentTimeInternal());
+ player->setCurrentTimeInternal(15);
+ player->setSource(source2.get());
+ EXPECT_EQ(15, player->currentTimeInternal());
+ EXPECT_EQ(0, source1->player());
+ EXPECT_EQ(player.get(), source2->player());
+ EXPECT_EQ(source2, player->source());
+}
+
+TEST_F(AnimationAnimationPlayerTest, SetSourceLimitsAnimationPlayer)
+{
+ player->setCurrentTimeInternal(20);
+ player->setSource(makeAnimation(10).get());
+ EXPECT_EQ(20, player->currentTimeInternal());
+ EXPECT_TRUE(player->finished());
+ updateTimeline(10);
+ EXPECT_EQ(20, player->currentTimeInternal());
+}
+
+TEST_F(AnimationAnimationPlayerTest, SetSourceUnlimitsAnimationPlayer)
+{
+ player->setCurrentTimeInternal(40);
+ player->setSource(makeAnimation(60).get());
+ EXPECT_FALSE(player->finished());
+ EXPECT_EQ(40, player->currentTimeInternal());
+ updateTimeline(10);
+ EXPECT_EQ(50, player->currentTimeInternal());
+}
+
+
+TEST_F(AnimationAnimationPlayerTest, EmptyAnimationPlayersDontUpdateEffects)
+{
+ player = timeline->createAnimationPlayer(0);
+ player->update(TimingUpdateOnDemand);
+ EXPECT_EQ(std::numeric_limits<double>::infinity(), player->timeToEffectChange());
+
+ updateTimeline(1234);
+ EXPECT_EQ(std::numeric_limits<double>::infinity(), player->timeToEffectChange());
+}
+
+TEST_F(AnimationAnimationPlayerTest, AnimationPlayersDisassociateFromSource)
+{
+ AnimationNode* animationNode = player->source();
+ AnimationPlayer* player2 = timeline->createAnimationPlayer(animationNode);
+ EXPECT_EQ(0, player->source());
+ player->setSource(animationNode);
+ EXPECT_EQ(0, player2->source());
+}
+
+TEST_F(AnimationAnimationPlayerTest, AnimationPlayersReturnTimeToNextEffect)
+{
+ Timing timing;
+ timing.startDelay = 1;
+ timing.iterationDuration = 1;
+ timing.endDelay = 1;
+ RefPtrWillBeRawPtr<Animation> animation = Animation::create(0, nullptr, timing);
+ player = timeline->createAnimationPlayer(animation.get());
+ player->setStartTimeInternal(0);
+
+ updateTimeline(0);
+ EXPECT_EQ(1, player->timeToEffectChange());
+
+ updateTimeline(0.5);
+ EXPECT_EQ(0.5, player->timeToEffectChange());
+
+ updateTimeline(1);
+ EXPECT_EQ(0, player->timeToEffectChange());
+
+ updateTimeline(1.5);
+ EXPECT_EQ(0, player->timeToEffectChange());
+
+ updateTimeline(2);
+ EXPECT_EQ(std::numeric_limits<double>::infinity(), player->timeToEffectChange());
+
+ updateTimeline(3);
+ EXPECT_EQ(std::numeric_limits<double>::infinity(), player->timeToEffectChange());
+
+ player->setCurrentTimeInternal(0);
+ player->update(TimingUpdateOnDemand);
+ EXPECT_EQ(1, player->timeToEffectChange());
+
+ player->setPlaybackRate(2);
+ player->update(TimingUpdateOnDemand);
+ EXPECT_EQ(0.5, player->timeToEffectChange());
+
+ player->setPlaybackRate(0);
+ player->update(TimingUpdateOnDemand);
+ EXPECT_EQ(std::numeric_limits<double>::infinity(), player->timeToEffectChange());
+
+ player->setCurrentTimeInternal(3);
+ player->setPlaybackRate(-1);
+ player->update(TimingUpdateOnDemand);
+ EXPECT_EQ(1, player->timeToEffectChange());
+
+ player->setPlaybackRate(-2);
+ player->update(TimingUpdateOnDemand);
+ EXPECT_EQ(0.5, player->timeToEffectChange());
+}
+
+TEST_F(AnimationAnimationPlayerTest, TimeToNextEffectWhenPaused)
+{
+ EXPECT_EQ(0, player->timeToEffectChange());
+ player->pause();
+ player->update(TimingUpdateOnDemand);
+ EXPECT_EQ(std::numeric_limits<double>::infinity(), player->timeToEffectChange());
+}
+
+TEST_F(AnimationAnimationPlayerTest, TimeToNextEffectWhenCancelledBeforeStart)
+{
+ EXPECT_EQ(0, player->timeToEffectChange());
+ player->setCurrentTimeInternal(-8);
+ player->setPlaybackRate(2);
+ player->cancel();
+ player->update(TimingUpdateOnDemand);
+ EXPECT_EQ(4, player->timeToEffectChange());
+}
+
+TEST_F(AnimationAnimationPlayerTest, TimeToNextEffectWhenCancelledBeforeStartReverse)
+{
+ EXPECT_EQ(0, player->timeToEffectChange());
+ player->setCurrentTimeInternal(9);
+ player->setPlaybackRate(-3);
+ player->cancel();
+ player->update(TimingUpdateOnDemand);
+ EXPECT_EQ(3, player->timeToEffectChange());
+}
+
+TEST_F(AnimationAnimationPlayerTest, AttachedAnimationPlayers)
+{
+ RefPtrWillBePersistent<Element> element = document->createElement("foo", ASSERT_NO_EXCEPTION);
+
+ Timing timing;
+ RefPtrWillBeRawPtr<Animation> animation = Animation::create(element.get(), nullptr, timing);
+ RefPtrWillBeRawPtr<AnimationPlayer> player = timeline->createAnimationPlayer(animation.get());
+ player->setStartTime(0);
+ timeline->serviceAnimations(TimingUpdateForAnimationFrame);
+ EXPECT_EQ(1, element->activeAnimations()->players().find(player.get())->value);
+
+ player.release();
+ Heap::collectAllGarbage();
+ EXPECT_TRUE(element->activeAnimations()->players().isEmpty());
+}
+
+TEST_F(AnimationAnimationPlayerTest, HasLowerPriority)
+{
+ // Sort time defaults to timeline current time
+ updateTimeline(15);
+ RefPtrWillBeRawPtr<AnimationPlayer> player1 = timeline->createAnimationPlayer(0);
+ RefPtrWillBeRawPtr<AnimationPlayer> player2 = timeline->createAnimationPlayer(0);
+ player2->setStartTimeInternal(10);
+ RefPtrWillBeRawPtr<AnimationPlayer> player3 = timeline->createAnimationPlayer(0);
+ RefPtrWillBeRawPtr<AnimationPlayer> player4 = timeline->createAnimationPlayer(0);
+ player4->setStartTimeInternal(20);
+ RefPtrWillBeRawPtr<AnimationPlayer> player5 = timeline->createAnimationPlayer(0);
+ player5->setStartTimeInternal(10);
+ RefPtrWillBeRawPtr<AnimationPlayer> player6 = timeline->createAnimationPlayer(0);
+ player6->setStartTimeInternal(-10);
+ Vector<RefPtrWillBeMember<AnimationPlayer> > players;
+ players.append(player6);
+ players.append(player2);
+ players.append(player5);
+ players.append(player1);
+ players.append(player3);
+ players.append(player4);
+ for (size_t i = 0; i < players.size(); i++) {
+ for (size_t j = 0; j < players.size(); j++)
+ EXPECT_EQ(i < j, AnimationPlayer::hasLowerPriority(players[i].get(), players[j].get()));
+ }
+}
+
+}
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimationStack.cpp b/chromium/third_party/WebKit/Source/core/animation/AnimationStack.cpp
index 601e7e598e4..7b840a16e8f 100644
--- a/chromium/third_party/WebKit/Source/core/animation/AnimationStack.cpp
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimationStack.cpp
@@ -32,25 +32,49 @@
#include "core/animation/AnimationStack.h"
#include "core/animation/css/CSSAnimations.h"
+#include "core/animation/interpolation/StyleInterpolation.h"
+#include "wtf/BitArray.h"
+#include "wtf/NonCopyingSort.h"
+#include <algorithm>
namespace WebCore {
namespace {
-void copyToCompositableValueMap(const AnimationEffect::CompositableValueList* source, AnimationEffect::CompositableValueMap& target)
+void copyToActiveInterpolationMap(const WillBeHeapVector<RefPtrWillBeMember<WebCore::Interpolation> >& source, WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<WebCore::Interpolation> >& target)
{
- if (!source)
- return;
- for (AnimationEffect::CompositableValueList::const_iterator iter = source->begin(); iter != source->end(); ++iter)
- target.set(iter->first, iter->second);
+ for (size_t i = 0; i < source.size(); ++i) {
+ Interpolation* interpolation = source[i].get();
+ target.set(toStyleInterpolation(interpolation)->id(), interpolation);
+ }
+}
+
+bool compareEffects(const OwnPtrWillBeMember<SampledEffect>& effect1, const OwnPtrWillBeMember<SampledEffect>& effect2)
+{
+ ASSERT(effect1 && effect2);
+ return effect1->sortInfo() < effect2->sortInfo();
+}
+
+void copyNewAnimationsToActiveInterpolationMap(const WillBeHeapVector<RawPtrWillBeMember<InertAnimation> >& newAnimations, WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> >& result)
+{
+ for (size_t i = 0; i < newAnimations.size(); ++i) {
+ OwnPtrWillBeRawPtr<WillBeHeapVector<RefPtrWillBeMember<Interpolation> > > sample = newAnimations[i]->sample(0);
+ if (sample) {
+ copyToActiveInterpolationMap(*sample, result);
+ }
+ }
}
} // namespace
+AnimationStack::AnimationStack()
+{
+}
+
bool AnimationStack::affects(CSSPropertyID property) const
{
- for (size_t i = 0; i < m_activeAnimations.size(); ++i) {
- if (m_activeAnimations[i]->affects(property))
+ for (size_t i = 0; i < m_effects.size(); ++i) {
+ if (m_effects[i]->animation() && m_effects[i]->animation()->affects(property))
return true;
}
return false;
@@ -58,35 +82,71 @@ bool AnimationStack::affects(CSSPropertyID property) const
bool AnimationStack::hasActiveAnimationsOnCompositor(CSSPropertyID property) const
{
- for (size_t i = 0; i < m_activeAnimations.size(); ++i) {
- if (m_activeAnimations[i]->hasActiveAnimationsOnCompositor(property))
+ for (size_t i = 0; i < m_effects.size(); ++i) {
+ if (m_effects[i]->animation() && m_effects[i]->animation()->hasActiveAnimationsOnCompositor(property))
return true;
}
return false;
}
-AnimationEffect::CompositableValueMap AnimationStack::compositableValues(const AnimationStack* animationStack, const Vector<InertAnimation*>* newAnimations, const HashSet<const Player*>* cancelledPlayers, Animation::Priority priority)
+WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> > AnimationStack::activeInterpolations(AnimationStack* animationStack, const WillBeHeapVector<RawPtrWillBeMember<InertAnimation> >* newAnimations, const WillBeHeapHashSet<RawPtrWillBeMember<const AnimationPlayer> >* cancelledAnimationPlayers, Animation::Priority priority, double timelineCurrentTime)
{
- AnimationEffect::CompositableValueMap result;
+ // We don't exactly know when new animations will start, but timelineCurrentTime is a good estimate.
+
+ WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> > result;
if (animationStack) {
- const Vector<Animation*>& animations = animationStack->m_activeAnimations;
- for (size_t i = 0; i < animations.size(); ++i) {
- Animation* animation = animations[i];
- if (animation->priority() != priority)
- continue;
- if (cancelledPlayers && cancelledPlayers->contains(animation->player()))
+ WillBeHeapVector<OwnPtrWillBeMember<SampledEffect> >& effects = animationStack->m_effects;
+ // std::sort doesn't work with OwnPtrs
+ nonCopyingSort(effects.begin(), effects.end(), compareEffects);
+ animationStack->simplifyEffects();
+ for (size_t i = 0; i < effects.size(); ++i) {
+ const SampledEffect& effect = *effects[i];
+ if (effect.priority() != priority || (cancelledAnimationPlayers && effect.animation() && cancelledAnimationPlayers->contains(effect.animation()->player())))
continue;
- copyToCompositableValueMap(animation->compositableValues(), result);
+ if (newAnimations && effect.sortInfo().startTime() > timelineCurrentTime) {
+ copyNewAnimationsToActiveInterpolationMap(*newAnimations, result);
+ newAnimations = 0;
+ }
+ copyToActiveInterpolationMap(effect.interpolations(), result);
}
}
- if (newAnimations) {
- for (size_t i = 0; i < newAnimations->size(); ++i)
- copyToCompositableValueMap(newAnimations->at(i)->sample().get(), result);
- }
+ if (newAnimations)
+ copyNewAnimationsToActiveInterpolationMap(*newAnimations, result);
return result;
}
+void AnimationStack::simplifyEffects()
+{
+ // FIXME: This will need to be updated when we have 'add' keyframes.
+
+ BitArray<numCSSProperties> replacedProperties;
+ for (size_t i = m_effects.size(); i--; ) {
+ SampledEffect& effect = *m_effects[i];
+ effect.removeReplacedInterpolationsIfNeeded(replacedProperties);
+ if (!effect.canChange()) {
+ for (size_t i = 0; i < effect.interpolations().size(); ++i)
+ replacedProperties.set(toStyleInterpolation(effect.interpolations()[i].get())->id());
+ }
+ }
+
+ size_t dest = 0;
+ for (size_t i = 0; i < m_effects.size(); ++i) {
+ if (!m_effects[i]->interpolations().isEmpty()) {
+ m_effects[dest++].swap(m_effects[i]);
+ continue;
+ }
+ if (m_effects[i]->animation())
+ m_effects[i]->animation()->notifySampledEffectRemovedFromAnimationStack();
+ }
+ m_effects.shrink(dest);
+}
+
+void AnimationStack::trace(Visitor* visitor)
+{
+ visitor->trace(m_effects);
+}
+
} // namespace WebCore
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimationStack.h b/chromium/third_party/WebKit/Source/core/animation/AnimationStack.h
index e7ad32f10b5..83371e8554f 100644
--- a/chromium/third_party/WebKit/Source/core/animation/AnimationStack.h
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimationStack.h
@@ -33,6 +33,8 @@
#include "core/animation/Animation.h"
#include "core/animation/AnimationEffect.h"
+#include "core/animation/AnimationPlayer.h"
+#include "core/animation/SampledEffect.h"
#include "wtf/HashSet.h"
#include "wtf/Vector.h"
@@ -41,22 +43,25 @@ namespace WebCore {
class InertAnimation;
class AnimationStack {
-
+ DISALLOW_ALLOCATION();
+ WTF_MAKE_NONCOPYABLE(AnimationStack);
public:
- void add(Animation* animation) { m_activeAnimations.append(animation); }
- void remove(Animation* animation)
- {
- size_t position = m_activeAnimations.find(animation);
- ASSERT(position != kNotFound);
- m_activeAnimations.remove(position);
- }
- bool isEmpty() const { return m_activeAnimations.isEmpty(); }
+ AnimationStack();
+
+ void add(PassOwnPtrWillBeRawPtr<SampledEffect> effect) { m_effects.append(effect); }
+ bool isEmpty() const { return m_effects.isEmpty(); }
bool affects(CSSPropertyID) const;
bool hasActiveAnimationsOnCompositor(CSSPropertyID) const;
- static AnimationEffect::CompositableValueMap compositableValues(const AnimationStack*, const Vector<InertAnimation*>* newAnimations, const HashSet<const Player*>* cancelledPlayers, Animation::Priority);
+ static WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> > activeInterpolations(AnimationStack*, const WillBeHeapVector<RawPtrWillBeMember<InertAnimation> >* newAnimations, const WillBeHeapHashSet<RawPtrWillBeMember<const AnimationPlayer> >* cancelledAnimationPlayers, Animation::Priority, double timelineCurrentTime);
+
+ void trace(Visitor*);
private:
- Vector<Animation*> m_activeAnimations;
+ void simplifyEffects();
+ // Effects sorted by priority. Lower priority at the start of the list.
+ WillBeHeapVector<OwnPtrWillBeMember<SampledEffect> > m_effects;
+
+ friend class AnimationAnimationStackTest;
};
} // namespace WebCore
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimationStackTest.cpp b/chromium/third_party/WebKit/Source/core/animation/AnimationStackTest.cpp
new file mode 100644
index 00000000000..5ebdf835d6f
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimationStackTest.cpp
@@ -0,0 +1,163 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "config.h"
+#include "core/animation/AnimationStack.h"
+
+#include "core/animation/ActiveAnimations.h"
+#include "core/animation/AnimatableDouble.h"
+#include "core/animation/AnimationClock.h"
+#include "core/animation/AnimationTimeline.h"
+#include "core/animation/KeyframeEffectModel.h"
+#include "core/animation/interpolation/LegacyStyleInterpolation.h"
+#include <gtest/gtest.h>
+
+namespace WebCore {
+
+class AnimationAnimationStackTest : public ::testing::Test {
+protected:
+ virtual void SetUp()
+ {
+ document = Document::create();
+ document->animationClock().resetTimeForTesting();
+ timeline = AnimationTimeline::create(document.get());
+ element = document->createElement("foo", ASSERT_NO_EXCEPTION);
+ }
+
+ AnimationPlayer* play(Animation* animation, double startTime)
+ {
+ AnimationPlayer* player = timeline->createAnimationPlayer(animation);
+ player->setStartTimeInternal(startTime);
+ player->update(TimingUpdateOnDemand);
+ return player;
+ }
+
+ void updateTimeline(double time)
+ {
+ document->animationClock().updateTime(time);
+ timeline->serviceAnimations(TimingUpdateForAnimationFrame);
+ }
+
+ const WillBeHeapVector<OwnPtrWillBeMember<SampledEffect> >& effects()
+ {
+ return element->ensureActiveAnimations().defaultStack().m_effects;
+ }
+
+ PassRefPtrWillBeRawPtr<AnimationEffect> makeAnimationEffect(CSSPropertyID id, PassRefPtrWillBeRawPtr<AnimatableValue> value)
+ {
+ AnimatableValueKeyframeVector keyframes(2);
+ keyframes[0] = AnimatableValueKeyframe::create();
+ keyframes[0]->setOffset(0.0);
+ keyframes[0]->setPropertyValue(id, value.get());
+ keyframes[1] = AnimatableValueKeyframe::create();
+ keyframes[1]->setOffset(1.0);
+ keyframes[1]->setPropertyValue(id, value.get());
+ return AnimatableValueKeyframeEffectModel::create(keyframes);
+ }
+
+ PassRefPtrWillBeRawPtr<InertAnimation> makeInertAnimation(PassRefPtrWillBeRawPtr<AnimationEffect> effect)
+ {
+ Timing timing;
+ timing.fillMode = Timing::FillModeBoth;
+ return InertAnimation::create(effect, timing, false);
+ }
+
+ PassRefPtrWillBeRawPtr<Animation> makeAnimation(PassRefPtrWillBeRawPtr<AnimationEffect> effect, double duration = 10)
+ {
+ Timing timing;
+ timing.fillMode = Timing::FillModeBoth;
+ timing.iterationDuration = duration;
+ return Animation::create(element.get(), effect, timing);
+ }
+
+ AnimatableValue* interpolationValue(Interpolation* interpolation)
+ {
+ return toLegacyStyleInterpolation(interpolation)->currentValue().get();
+ }
+
+ RefPtrWillBePersistent<Document> document;
+ RefPtrWillBePersistent<AnimationTimeline> timeline;
+ RefPtrWillBePersistent<Element> element;
+};
+
+TEST_F(AnimationAnimationStackTest, ActiveAnimationsSorted)
+{
+ play(makeAnimation(makeAnimationEffect(CSSPropertyFontSize, AnimatableDouble::create(1))).get(), 10);
+ play(makeAnimation(makeAnimationEffect(CSSPropertyFontSize, AnimatableDouble::create(2))).get(), 15);
+ play(makeAnimation(makeAnimationEffect(CSSPropertyFontSize, AnimatableDouble::create(3))).get(), 5);
+ WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> > result = AnimationStack::activeInterpolations(&element->activeAnimations()->defaultStack(), 0, 0, Animation::DefaultPriority, 0);
+ EXPECT_EQ(1u, result.size());
+ EXPECT_TRUE(interpolationValue(result.get(CSSPropertyFontSize))->equals(AnimatableDouble::create(2).get()));
+}
+
+TEST_F(AnimationAnimationStackTest, NewAnimations)
+{
+ play(makeAnimation(makeAnimationEffect(CSSPropertyFontSize, AnimatableDouble::create(1))).get(), 15);
+ play(makeAnimation(makeAnimationEffect(CSSPropertyZIndex, AnimatableDouble::create(2))).get(), 10);
+ WillBeHeapVector<RawPtrWillBeMember<InertAnimation> > newAnimations;
+ RefPtrWillBeRawPtr<InertAnimation> inert1 = makeInertAnimation(makeAnimationEffect(CSSPropertyFontSize, AnimatableDouble::create(3)));
+ RefPtrWillBeRawPtr<InertAnimation> inert2 = makeInertAnimation(makeAnimationEffect(CSSPropertyZIndex, AnimatableDouble::create(4)));
+ newAnimations.append(inert1.get());
+ newAnimations.append(inert2.get());
+ WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> > result = AnimationStack::activeInterpolations(&element->activeAnimations()->defaultStack(), &newAnimations, 0, Animation::DefaultPriority, 10);
+ EXPECT_EQ(2u, result.size());
+ EXPECT_TRUE(interpolationValue(result.get(CSSPropertyFontSize))->equals(AnimatableDouble::create(1).get()));
+ EXPECT_TRUE(interpolationValue(result.get(CSSPropertyZIndex))->equals(AnimatableDouble::create(4).get()));
+}
+
+TEST_F(AnimationAnimationStackTest, CancelledAnimationPlayers)
+{
+ WillBeHeapHashSet<RawPtrWillBeMember<const AnimationPlayer> > cancelledAnimationPlayers;
+ RefPtrWillBeRawPtr<AnimationPlayer> player = play(makeAnimation(makeAnimationEffect(CSSPropertyFontSize, AnimatableDouble::create(1))).get(), 0);
+ cancelledAnimationPlayers.add(player.get());
+ play(makeAnimation(makeAnimationEffect(CSSPropertyZIndex, AnimatableDouble::create(2))).get(), 0);
+ WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> > result = AnimationStack::activeInterpolations(&element->activeAnimations()->defaultStack(), 0, &cancelledAnimationPlayers, Animation::DefaultPriority, 0);
+ EXPECT_EQ(1u, result.size());
+ EXPECT_TRUE(interpolationValue(result.get(CSSPropertyZIndex))->equals(AnimatableDouble::create(2).get()));
+}
+
+TEST_F(AnimationAnimationStackTest, ForwardsFillDiscarding)
+{
+ play(makeAnimation(makeAnimationEffect(CSSPropertyFontSize, AnimatableDouble::create(1))).get(), 2);
+ play(makeAnimation(makeAnimationEffect(CSSPropertyFontSize, AnimatableDouble::create(2))).get(), 6);
+ play(makeAnimation(makeAnimationEffect(CSSPropertyFontSize, AnimatableDouble::create(3))).get(), 4);
+ document->compositorPendingAnimations().startPendingAnimations();
+ WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> > interpolations;
+
+ updateTimeline(11);
+ Heap::collectAllGarbage();
+ interpolations = AnimationStack::activeInterpolations(&element->activeAnimations()->defaultStack(), 0, 0, Animation::DefaultPriority, 0);
+ EXPECT_TRUE(interpolationValue(interpolations.get(CSSPropertyFontSize))->equals(AnimatableDouble::create(2).get()));
+ EXPECT_EQ(3u, effects().size());
+ EXPECT_EQ(1u, interpolations.size());
+ EXPECT_EQ(2, effects()[0]->sortInfo().startTime());
+ EXPECT_EQ(4, effects()[1]->sortInfo().startTime());
+ EXPECT_EQ(6, effects()[2]->sortInfo().startTime());
+
+ updateTimeline(13);
+ Heap::collectAllGarbage();
+ interpolations = AnimationStack::activeInterpolations(&element->activeAnimations()->defaultStack(), 0, 0, Animation::DefaultPriority, 0);
+ EXPECT_TRUE(interpolationValue(interpolations.get(CSSPropertyFontSize))->equals(AnimatableDouble::create(2).get()));
+ EXPECT_EQ(3u, effects().size());
+ EXPECT_EQ(2, effects()[0]->sortInfo().startTime());
+ EXPECT_EQ(4, effects()[1]->sortInfo().startTime());
+ EXPECT_EQ(6, effects()[2]->sortInfo().startTime());
+
+ updateTimeline(15);
+ Heap::collectAllGarbage();
+ interpolations = AnimationStack::activeInterpolations(&element->activeAnimations()->defaultStack(), 0, 0, Animation::DefaultPriority, 0);
+ EXPECT_TRUE(interpolationValue(interpolations.get(CSSPropertyFontSize))->equals(AnimatableDouble::create(2).get()));
+ EXPECT_EQ(2u, effects().size());
+ EXPECT_EQ(4, effects()[0]->sortInfo().startTime());
+ EXPECT_EQ(6, effects()[1]->sortInfo().startTime());
+
+ updateTimeline(17);
+ Heap::collectAllGarbage();
+ interpolations = AnimationStack::activeInterpolations(&element->activeAnimations()->defaultStack(), 0, 0, Animation::DefaultPriority, 0);
+ EXPECT_TRUE(interpolationValue(interpolations.get(CSSPropertyFontSize))->equals(AnimatableDouble::create(2).get()));
+ EXPECT_EQ(1u, effects().size());
+ EXPECT_EQ(6, effects()[0]->sortInfo().startTime());
+}
+
+}
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimationTest.cpp b/chromium/third_party/WebKit/Source/core/animation/AnimationTest.cpp
new file mode 100644
index 00000000000..2d6ea65a4fd
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimationTest.cpp
@@ -0,0 +1,467 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "config.h"
+#include "core/animation/Animation.h"
+
+#include "bindings/v8/Dictionary.h"
+#include "core/animation/AnimationClock.h"
+#include "core/animation/AnimationHelpers.h"
+#include "core/animation/AnimationNodeTiming.h"
+#include "core/animation/AnimationTestHelper.h"
+#include "core/animation/AnimationTimeline.h"
+#include "core/animation/KeyframeEffectModel.h"
+#include "core/animation/Timing.h"
+#include "core/dom/Document.h"
+#include <gtest/gtest.h>
+#include <v8.h>
+
+namespace WebCore {
+
+class AnimationAnimationTest : public ::testing::Test {
+protected:
+ AnimationAnimationTest()
+ : document(Document::create())
+ , element(document->createElement("foo", ASSERT_NO_EXCEPTION))
+ {
+ document->animationClock().resetTimeForTesting();
+ EXPECT_EQ(0, document->timeline().currentTime());
+ }
+
+ RefPtrWillBePersistent<Document> document;
+ RefPtrWillBePersistent<Element> element;
+ TrackExceptionState exceptionState;
+};
+
+class AnimationAnimationV8Test : public AnimationAnimationTest {
+protected:
+ AnimationAnimationV8Test()
+ : m_isolate(v8::Isolate::GetCurrent())
+ , m_scope(m_isolate)
+ {
+ }
+
+ template<typename T>
+ static PassRefPtrWillBeRawPtr<Animation> createAnimation(Element* element, Vector<Dictionary> keyframeDictionaryVector, T timingInput, ExceptionState& exceptionState)
+ {
+ return Animation::create(element, EffectInput::convert(element, keyframeDictionaryVector, exceptionState), timingInput);
+ }
+ static PassRefPtrWillBeRawPtr<Animation> createAnimation(Element* element, Vector<Dictionary> keyframeDictionaryVector, ExceptionState& exceptionState)
+ {
+ return Animation::create(element, EffectInput::convert(element, keyframeDictionaryVector, exceptionState));
+ }
+
+ v8::Isolate* m_isolate;
+
+private:
+ V8TestingScope m_scope;
+};
+
+TEST_F(AnimationAnimationV8Test, CanCreateAnAnimation)
+{
+ Vector<Dictionary> jsKeyframes;
+ v8::Handle<v8::Object> keyframe1 = v8::Object::New(m_isolate);
+ v8::Handle<v8::Object> keyframe2 = v8::Object::New(m_isolate);
+
+ setV8ObjectPropertyAsString(keyframe1, "width", "100px");
+ setV8ObjectPropertyAsString(keyframe1, "offset", "0");
+ setV8ObjectPropertyAsString(keyframe1, "easing", "ease-in-out");
+ setV8ObjectPropertyAsString(keyframe2, "width", "0px");
+ setV8ObjectPropertyAsString(keyframe2, "offset", "1");
+ setV8ObjectPropertyAsString(keyframe2, "easing", "cubic-bezier(1, 1, 0.3, 0.3)");
+
+ jsKeyframes.append(Dictionary(keyframe1, m_isolate));
+ jsKeyframes.append(Dictionary(keyframe2, m_isolate));
+
+ String value1;
+ ASSERT_TRUE(jsKeyframes[0].get("width", value1));
+ ASSERT_EQ("100px", value1);
+
+ String value2;
+ ASSERT_TRUE(jsKeyframes[1].get("width", value2));
+ ASSERT_EQ("0px", value2);
+
+ RefPtrWillBeRawPtr<Animation> animation = createAnimation(element.get(), jsKeyframes, 0, exceptionState);
+
+ Element* target = animation->target();
+ EXPECT_EQ(*element.get(), *target);
+
+ const KeyframeVector keyframes = toKeyframeEffectModelBase(animation->effect())->getFrames();
+
+ EXPECT_EQ(0, keyframes[0]->offset());
+ EXPECT_EQ(1, keyframes[1]->offset());
+
+ const CSSValue* keyframe1Width = toStringKeyframe(keyframes[0].get())->propertyValue(CSSPropertyWidth);
+ const CSSValue* keyframe2Width = toStringKeyframe(keyframes[1].get())->propertyValue(CSSPropertyWidth);
+ ASSERT(keyframe1Width);
+ ASSERT(keyframe2Width);
+
+ EXPECT_EQ("100px", keyframe1Width->cssText());
+ EXPECT_EQ("0px", keyframe2Width->cssText());
+
+ EXPECT_EQ(*(CubicBezierTimingFunction::preset(CubicBezierTimingFunction::EaseInOut)), *keyframes[0]->easing());
+ EXPECT_EQ(*(CubicBezierTimingFunction::create(1, 1, 0.3, 0.3).get()), *keyframes[1]->easing());
+}
+
+TEST_F(AnimationAnimationV8Test, CanSetDuration)
+{
+ Vector<Dictionary, 0> jsKeyframes;
+ double duration = 2000;
+
+ RefPtrWillBeRawPtr<Animation> animation = createAnimation(element.get(), jsKeyframes, duration, exceptionState);
+
+ EXPECT_EQ(duration / 1000, animation->specifiedTiming().iterationDuration);
+}
+
+TEST_F(AnimationAnimationV8Test, CanOmitSpecifiedDuration)
+{
+ Vector<Dictionary, 0> jsKeyframes;
+ RefPtrWillBeRawPtr<Animation> animation = createAnimation(element.get(), jsKeyframes, exceptionState);
+ EXPECT_TRUE(std::isnan(animation->specifiedTiming().iterationDuration));
+}
+
+TEST_F(AnimationAnimationV8Test, NegativeDurationIsAuto)
+{
+ Vector<Dictionary, 0> jsKeyframes;
+ RefPtrWillBeRawPtr<Animation> animation = createAnimation(element.get(), jsKeyframes, -2, exceptionState);
+ EXPECT_TRUE(std::isnan(animation->specifiedTiming().iterationDuration));
+}
+
+TEST_F(AnimationAnimationV8Test, MismatchedKeyframePropertyRaisesException)
+{
+ Vector<Dictionary> jsKeyframes;
+ v8::Handle<v8::Object> keyframe1 = v8::Object::New(m_isolate);
+ v8::Handle<v8::Object> keyframe2 = v8::Object::New(m_isolate);
+
+ setV8ObjectPropertyAsString(keyframe1, "width", "100px");
+ setV8ObjectPropertyAsString(keyframe1, "offset", "0");
+
+ // Height property appears only in keyframe2
+ setV8ObjectPropertyAsString(keyframe2, "height", "100px");
+ setV8ObjectPropertyAsString(keyframe2, "width", "0px");
+ setV8ObjectPropertyAsString(keyframe2, "offset", "1");
+
+ jsKeyframes.append(Dictionary(keyframe1, m_isolate));
+ jsKeyframes.append(Dictionary(keyframe2, m_isolate));
+
+ createAnimation(element.get(), jsKeyframes, 0, exceptionState);
+
+ EXPECT_TRUE(exceptionState.hadException());
+ EXPECT_EQ(NotSupportedError, exceptionState.code());
+}
+
+TEST_F(AnimationAnimationV8Test, MissingOffsetZeroRaisesException)
+{
+ Vector<Dictionary> jsKeyframes;
+ v8::Handle<v8::Object> keyframe1 = v8::Object::New(m_isolate);
+ v8::Handle<v8::Object> keyframe2 = v8::Object::New(m_isolate);
+
+ setV8ObjectPropertyAsString(keyframe1, "width", "100px");
+ setV8ObjectPropertyAsString(keyframe1, "offset", "0.1");
+ setV8ObjectPropertyAsString(keyframe2, "width", "0px");
+ setV8ObjectPropertyAsString(keyframe2, "offset", "1");
+
+ jsKeyframes.append(Dictionary(keyframe1, m_isolate));
+ jsKeyframes.append(Dictionary(keyframe2, m_isolate));
+
+ createAnimation(element.get(), jsKeyframes, 0, exceptionState);
+
+ EXPECT_TRUE(exceptionState.hadException());
+ EXPECT_EQ(NotSupportedError, exceptionState.code());
+}
+
+TEST_F(AnimationAnimationV8Test, MissingOffsetOneRaisesException)
+{
+ Vector<Dictionary> jsKeyframes;
+ v8::Handle<v8::Object> keyframe1 = v8::Object::New(m_isolate);
+ v8::Handle<v8::Object> keyframe2 = v8::Object::New(m_isolate);
+
+ setV8ObjectPropertyAsString(keyframe1, "width", "100px");
+ setV8ObjectPropertyAsString(keyframe1, "offset", "0");
+ setV8ObjectPropertyAsString(keyframe2, "width", "0px");
+ setV8ObjectPropertyAsString(keyframe2, "offset", "0.1");
+
+ jsKeyframes.append(Dictionary(keyframe1, m_isolate));
+ jsKeyframes.append(Dictionary(keyframe2, m_isolate));
+
+ createAnimation(element.get(), jsKeyframes, 0, exceptionState);
+
+ EXPECT_TRUE(exceptionState.hadException());
+ EXPECT_EQ(NotSupportedError, exceptionState.code());
+}
+
+TEST_F(AnimationAnimationV8Test, MissingOffsetZeroAndOneRaisesException)
+{
+ Vector<Dictionary> jsKeyframes;
+ v8::Handle<v8::Object> keyframe1 = v8::Object::New(m_isolate);
+ v8::Handle<v8::Object> keyframe2 = v8::Object::New(m_isolate);
+
+ setV8ObjectPropertyAsString(keyframe1, "width", "100px");
+ setV8ObjectPropertyAsString(keyframe1, "offset", "0.1");
+ setV8ObjectPropertyAsString(keyframe2, "width", "0px");
+ setV8ObjectPropertyAsString(keyframe2, "offset", "0.2");
+
+ jsKeyframes.append(Dictionary(keyframe1, m_isolate));
+ jsKeyframes.append(Dictionary(keyframe2, m_isolate));
+
+ createAnimation(element.get(), jsKeyframes, 0, exceptionState);
+
+ EXPECT_TRUE(exceptionState.hadException());
+ EXPECT_EQ(NotSupportedError, exceptionState.code());
+}
+
+TEST_F(AnimationAnimationV8Test, SpecifiedGetters)
+{
+ Vector<Dictionary, 0> jsKeyframes;
+
+ v8::Handle<v8::Object> timingInput = v8::Object::New(m_isolate);
+ setV8ObjectPropertyAsNumber(timingInput, "delay", 2);
+ setV8ObjectPropertyAsNumber(timingInput, "endDelay", 0.5);
+ setV8ObjectPropertyAsString(timingInput, "fill", "backwards");
+ setV8ObjectPropertyAsNumber(timingInput, "iterationStart", 2);
+ setV8ObjectPropertyAsNumber(timingInput, "iterations", 10);
+ setV8ObjectPropertyAsNumber(timingInput, "playbackRate", 2);
+ setV8ObjectPropertyAsString(timingInput, "direction", "reverse");
+ setV8ObjectPropertyAsString(timingInput, "easing", "step-start");
+ Dictionary timingInputDictionary = Dictionary(v8::Handle<v8::Value>::Cast(timingInput), m_isolate);
+
+ RefPtrWillBeRawPtr<Animation> animation = createAnimation(element.get(), jsKeyframes, timingInputDictionary, exceptionState);
+
+ RefPtrWillBeRawPtr<AnimationNodeTiming> specified = animation->timing();
+ EXPECT_EQ(2, specified->delay());
+ EXPECT_EQ(0.5, specified->endDelay());
+ EXPECT_EQ("backwards", specified->fill());
+ EXPECT_EQ(2, specified->iterationStart());
+ EXPECT_EQ(10, specified->iterations());
+ EXPECT_EQ(2, specified->playbackRate());
+ EXPECT_EQ("reverse", specified->direction());
+ EXPECT_EQ("step-start", specified->easing());
+}
+
+TEST_F(AnimationAnimationV8Test, SpecifiedDurationGetter)
+{
+ Vector<Dictionary, 0> jsKeyframes;
+
+ v8::Handle<v8::Object> timingInputWithDuration = v8::Object::New(m_isolate);
+ setV8ObjectPropertyAsNumber(timingInputWithDuration, "duration", 2.5);
+ Dictionary timingInputDictionaryWithDuration = Dictionary(v8::Handle<v8::Value>::Cast(timingInputWithDuration), m_isolate);
+
+ RefPtrWillBeRawPtr<Animation> animationWithDuration = createAnimation(element.get(), jsKeyframes, timingInputDictionaryWithDuration, exceptionState);
+
+ RefPtrWillBeRawPtr<AnimationNodeTiming> specifiedWithDuration = animationWithDuration->timing();
+ bool isNumber = false;
+ double numberDuration = std::numeric_limits<double>::quiet_NaN();
+ bool isString = false;
+ String stringDuration = "";
+ specifiedWithDuration->getDuration("duration", isNumber, numberDuration, isString, stringDuration);
+ EXPECT_TRUE(isNumber);
+ EXPECT_EQ(2.5, numberDuration);
+ EXPECT_FALSE(isString);
+ EXPECT_EQ("", stringDuration);
+
+
+ v8::Handle<v8::Object> timingInputNoDuration = v8::Object::New(m_isolate);
+ Dictionary timingInputDictionaryNoDuration = Dictionary(v8::Handle<v8::Value>::Cast(timingInputNoDuration), m_isolate);
+
+ RefPtrWillBeRawPtr<Animation> animationNoDuration = createAnimation(element.get(), jsKeyframes, timingInputDictionaryNoDuration, exceptionState);
+
+ RefPtrWillBeRawPtr<AnimationNodeTiming> specifiedNoDuration = animationNoDuration->timing();
+ isNumber = false;
+ numberDuration = std::numeric_limits<double>::quiet_NaN();
+ isString = false;
+ stringDuration = "";
+ specifiedNoDuration->getDuration("duration", isNumber, numberDuration, isString, stringDuration);
+ EXPECT_FALSE(isNumber);
+ EXPECT_TRUE(std::isnan(numberDuration));
+ EXPECT_TRUE(isString);
+ EXPECT_EQ("auto", stringDuration);
+}
+
+TEST_F(AnimationAnimationV8Test, SpecifiedSetters)
+{
+ Vector<Dictionary, 0> jsKeyframes;
+ v8::Handle<v8::Object> timingInput = v8::Object::New(m_isolate);
+ Dictionary timingInputDictionary = Dictionary(v8::Handle<v8::Value>::Cast(timingInput), m_isolate);
+ RefPtrWillBeRawPtr<Animation> animation = createAnimation(element.get(), jsKeyframes, timingInputDictionary, exceptionState);
+
+ RefPtrWillBeRawPtr<AnimationNodeTiming> specified = animation->timing();
+
+ EXPECT_EQ(0, specified->delay());
+ specified->setDelay(2);
+ EXPECT_EQ(2, specified->delay());
+
+ EXPECT_EQ(0, specified->endDelay());
+ specified->setEndDelay(0.5);
+ EXPECT_EQ(0.5, specified->endDelay());
+
+ EXPECT_EQ("auto", specified->fill());
+ specified->setFill("backwards");
+ EXPECT_EQ("backwards", specified->fill());
+
+ EXPECT_EQ(0, specified->iterationStart());
+ specified->setIterationStart(2);
+ EXPECT_EQ(2, specified->iterationStart());
+
+ EXPECT_EQ(1, specified->iterations());
+ specified->setIterations(10);
+ EXPECT_EQ(10, specified->iterations());
+
+ EXPECT_EQ(1, specified->playbackRate());
+ specified->setPlaybackRate(2);
+ EXPECT_EQ(2, specified->playbackRate());
+
+ EXPECT_EQ("normal", specified->direction());
+ specified->setDirection("reverse");
+ EXPECT_EQ("reverse", specified->direction());
+
+ EXPECT_EQ("linear", specified->easing());
+ specified->setEasing("step-start");
+ EXPECT_EQ("step-start", specified->easing());
+}
+
+TEST_F(AnimationAnimationV8Test, SetSpecifiedDuration)
+{
+ Vector<Dictionary, 0> jsKeyframes;
+ v8::Handle<v8::Object> timingInput = v8::Object::New(m_isolate);
+ Dictionary timingInputDictionary = Dictionary(v8::Handle<v8::Value>::Cast(timingInput), m_isolate);
+ RefPtrWillBeRawPtr<Animation> animation = createAnimation(element.get(), jsKeyframes, timingInputDictionary, exceptionState);
+
+ RefPtrWillBeRawPtr<AnimationNodeTiming> specified = animation->timing();
+
+ bool isNumber = false;
+ double numberDuration = std::numeric_limits<double>::quiet_NaN();
+ bool isString = false;
+ String stringDuration = "";
+ specified->getDuration("duration", isNumber, numberDuration, isString, stringDuration);
+ EXPECT_FALSE(isNumber);
+ EXPECT_TRUE(std::isnan(numberDuration));
+ EXPECT_TRUE(isString);
+ EXPECT_EQ("auto", stringDuration);
+
+ specified->setDuration("duration", 2.5);
+ isNumber = false;
+ numberDuration = std::numeric_limits<double>::quiet_NaN();
+ isString = false;
+ stringDuration = "";
+ specified->getDuration("duration", isNumber, numberDuration, isString, stringDuration);
+ EXPECT_TRUE(isNumber);
+ EXPECT_EQ(2.5, numberDuration);
+ EXPECT_FALSE(isString);
+ EXPECT_EQ("", stringDuration);
+}
+
+TEST_F(AnimationAnimationTest, TimeToEffectChange)
+{
+ Timing timing;
+ timing.iterationDuration = 100;
+ timing.startDelay = 100;
+ timing.endDelay = 100;
+ timing.fillMode = Timing::FillModeNone;
+ RefPtrWillBeRawPtr<Animation> animation = Animation::create(0, nullptr, timing);
+ RefPtrWillBeRawPtr<AnimationPlayer> player = document->timeline().play(animation.get());
+ double inf = std::numeric_limits<double>::infinity();
+
+ EXPECT_EQ(100, animation->timeToForwardsEffectChange());
+ EXPECT_EQ(inf, animation->timeToReverseEffectChange());
+
+ player->setCurrentTimeInternal(100);
+ EXPECT_EQ(0, animation->timeToForwardsEffectChange());
+ EXPECT_EQ(0, animation->timeToReverseEffectChange());
+
+ player->setCurrentTimeInternal(199);
+ EXPECT_EQ(0, animation->timeToForwardsEffectChange());
+ EXPECT_EQ(0, animation->timeToReverseEffectChange());
+
+ player->setCurrentTimeInternal(200);
+ // End-exclusive.
+ EXPECT_EQ(inf, animation->timeToForwardsEffectChange());
+ EXPECT_EQ(0, animation->timeToReverseEffectChange());
+
+ player->setCurrentTimeInternal(300);
+ EXPECT_EQ(inf, animation->timeToForwardsEffectChange());
+ EXPECT_EQ(100, animation->timeToReverseEffectChange());
+}
+
+TEST_F(AnimationAnimationTest, TimeToEffectChangeWithPlaybackRate)
+{
+ Timing timing;
+ timing.iterationDuration = 100;
+ timing.startDelay = 100;
+ timing.endDelay = 100;
+ timing.playbackRate = 2;
+ timing.fillMode = Timing::FillModeNone;
+ RefPtrWillBeRawPtr<Animation> animation = Animation::create(0, nullptr, timing);
+ RefPtrWillBeRawPtr<AnimationPlayer> player = document->timeline().play(animation.get());
+ double inf = std::numeric_limits<double>::infinity();
+
+ EXPECT_EQ(100, animation->timeToForwardsEffectChange());
+ EXPECT_EQ(inf, animation->timeToReverseEffectChange());
+
+ player->setCurrentTimeInternal(100);
+ EXPECT_EQ(0, animation->timeToForwardsEffectChange());
+ EXPECT_EQ(0, animation->timeToReverseEffectChange());
+
+ player->setCurrentTimeInternal(149);
+ EXPECT_EQ(0, animation->timeToForwardsEffectChange());
+ EXPECT_EQ(0, animation->timeToReverseEffectChange());
+
+ player->setCurrentTimeInternal(150);
+ // End-exclusive.
+ EXPECT_EQ(inf, animation->timeToForwardsEffectChange());
+ EXPECT_EQ(0, animation->timeToReverseEffectChange());
+
+ player->setCurrentTimeInternal(200);
+ EXPECT_EQ(inf, animation->timeToForwardsEffectChange());
+ EXPECT_EQ(50, animation->timeToReverseEffectChange());
+}
+
+TEST_F(AnimationAnimationTest, TimeToEffectChangeWithNegativePlaybackRate)
+{
+ Timing timing;
+ timing.iterationDuration = 100;
+ timing.startDelay = 100;
+ timing.endDelay = 100;
+ timing.playbackRate = -2;
+ timing.fillMode = Timing::FillModeNone;
+ RefPtrWillBeRawPtr<Animation> animation = Animation::create(0, nullptr, timing);
+ RefPtrWillBeRawPtr<AnimationPlayer> player = document->timeline().play(animation.get());
+ double inf = std::numeric_limits<double>::infinity();
+
+ EXPECT_EQ(100, animation->timeToForwardsEffectChange());
+ EXPECT_EQ(inf, animation->timeToReverseEffectChange());
+
+ player->setCurrentTimeInternal(100);
+ EXPECT_EQ(0, animation->timeToForwardsEffectChange());
+ EXPECT_EQ(0, animation->timeToReverseEffectChange());
+
+ player->setCurrentTimeInternal(149);
+ EXPECT_EQ(0, animation->timeToForwardsEffectChange());
+ EXPECT_EQ(0, animation->timeToReverseEffectChange());
+
+ player->setCurrentTimeInternal(150);
+ EXPECT_EQ(inf, animation->timeToForwardsEffectChange());
+ EXPECT_EQ(0, animation->timeToReverseEffectChange());
+
+ player->setCurrentTimeInternal(200);
+ EXPECT_EQ(inf, animation->timeToForwardsEffectChange());
+ EXPECT_EQ(50, animation->timeToReverseEffectChange());
+}
+
+TEST_F(AnimationAnimationTest, ElementDestructorClearsAnimationTarget)
+{
+ // This test expects incorrect behaviour should be removed once Element
+ // and Animation are moved to Oilpan. See crbug.com/362404 for context.
+ Timing timing;
+ timing.iterationDuration = 5;
+ RefPtrWillBeRawPtr<Animation> animation = Animation::create(element.get(), nullptr, timing);
+ EXPECT_EQ(element.get(), animation->target());
+ document->timeline().play(animation.get());
+ document.clear();
+ element.clear();
+#if !ENABLE(OILPAN)
+ EXPECT_EQ(0, animation->target());
+#endif
+}
+
+} // namespace WebCore
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimationTestHelper.cpp b/chromium/third_party/WebKit/Source/core/animation/AnimationTestHelper.cpp
new file mode 100644
index 00000000000..12f4e378527
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimationTestHelper.cpp
@@ -0,0 +1,32 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "config.h"
+#include "core/animation/AnimationTestHelper.h"
+
+#include "bindings/v8/V8Binding.h"
+
+namespace WebCore {
+
+v8::Handle<v8::Value> stringToV8Value(String string)
+{
+ return v8::Handle<v8::Value>::Cast(v8String(v8::Isolate::GetCurrent(), string));
+}
+
+v8::Handle<v8::Value> doubleToV8Value(double number)
+{
+ return v8::Handle<v8::Value>::Cast(v8::Number::New(v8::Isolate::GetCurrent(), number));
+}
+
+void setV8ObjectPropertyAsString(v8::Handle<v8::Object> object, String name, String value)
+{
+ object->Set(stringToV8Value(name), stringToV8Value(value));
+}
+
+void setV8ObjectPropertyAsNumber(v8::Handle<v8::Object> object, String name, double value)
+{
+ object->Set(stringToV8Value(name), doubleToV8Value(value));
+}
+
+} // namespace WebCore
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimationTestHelper.h b/chromium/third_party/WebKit/Source/core/animation/AnimationTestHelper.h
new file mode 100644
index 00000000000..5d20c7c7152
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimationTestHelper.h
@@ -0,0 +1,23 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef AnimationTestHelper_h
+#define AnimationTestHelper_h
+
+#include "wtf/text/WTFString.h"
+#include <v8.h>
+
+namespace WebCore {
+
+v8::Handle<v8::Value> stringToV8Value(String);
+
+v8::Handle<v8::Value> doubleToV8Value(double);
+
+void setV8ObjectPropertyAsString(v8::Handle<v8::Object>, String, String);
+
+void setV8ObjectPropertyAsNumber(v8::Handle<v8::Object>, String, double);
+
+} // namespace WebCore
+
+#endif // AnimationTestHelper_h
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimationTimeline.cpp b/chromium/third_party/WebKit/Source/core/animation/AnimationTimeline.cpp
new file mode 100644
index 00000000000..4553fbe880f
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimationTimeline.cpp
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "core/animation/AnimationTimeline.h"
+
+#include "core/animation/ActiveAnimations.h"
+#include "core/animation/AnimationClock.h"
+#include "core/dom/Document.h"
+#include "core/frame/FrameView.h"
+#include "core/page/Page.h"
+#include "platform/TraceEvent.h"
+
+namespace WebCore {
+
+// This value represents 1 frame at 30Hz plus a little bit of wiggle room.
+// TODO: Plumb a nominal framerate through and derive this value from that.
+const double AnimationTimeline::s_minimumDelay = 0.04;
+
+
+PassRefPtrWillBeRawPtr<AnimationTimeline> AnimationTimeline::create(Document* document, PassOwnPtrWillBeRawPtr<PlatformTiming> timing)
+{
+ return adoptRefWillBeNoop(new AnimationTimeline(document, timing));
+}
+
+AnimationTimeline::AnimationTimeline(Document* document, PassOwnPtrWillBeRawPtr<PlatformTiming> timing)
+ : m_document(document)
+{
+ if (!timing)
+ m_timing = adoptPtrWillBeNoop(new AnimationTimelineTiming(this));
+ else
+ m_timing = timing;
+
+ ASSERT(document);
+}
+
+AnimationTimeline::~AnimationTimeline()
+{
+#if !ENABLE(OILPAN)
+ for (WillBeHeapHashSet<RawPtrWillBeWeakMember<AnimationPlayer> >::iterator it = m_players.begin(); it != m_players.end(); ++it)
+ (*it)->timelineDestroyed();
+#endif
+}
+
+AnimationPlayer* AnimationTimeline::createAnimationPlayer(AnimationNode* child)
+{
+ RefPtrWillBeRawPtr<AnimationPlayer> player = AnimationPlayer::create(m_document->contextDocument().get(), *this, child);
+ AnimationPlayer* result = player.get();
+ m_players.add(result);
+ setOutdatedAnimationPlayer(result);
+ return result;
+}
+
+AnimationPlayer* AnimationTimeline::play(AnimationNode* child)
+{
+ if (!m_document)
+ return 0;
+ AnimationPlayer* player = createAnimationPlayer(child);
+ m_document->compositorPendingAnimations().add(player);
+ return player;
+}
+
+void AnimationTimeline::wake()
+{
+ m_timing->serviceOnNextFrame();
+}
+
+void AnimationTimeline::serviceAnimations(TimingUpdateReason reason)
+{
+ TRACE_EVENT0("webkit", "AnimationTimeline::serviceAnimations");
+
+ m_timing->cancelWake();
+
+ double timeToNextEffect = std::numeric_limits<double>::infinity();
+ WillBeHeapVector<RawPtrWillBeMember<AnimationPlayer> > players;
+ for (WillBeHeapHashSet<RefPtrWillBeMember<AnimationPlayer> >::iterator it = m_playersNeedingUpdate.begin(); it != m_playersNeedingUpdate.end(); ++it)
+ players.append(it->get());
+
+ std::sort(players.begin(), players.end(), AnimationPlayer::hasLowerPriority);
+
+ for (size_t i = 0; i < players.size(); ++i) {
+ AnimationPlayer* player = players[i];
+ if (player->update(reason))
+ timeToNextEffect = std::min(timeToNextEffect, player->timeToEffectChange());
+ else
+ m_playersNeedingUpdate.remove(player);
+ }
+
+ if (timeToNextEffect < s_minimumDelay)
+ m_timing->serviceOnNextFrame();
+ else if (timeToNextEffect != std::numeric_limits<double>::infinity())
+ m_timing->wakeAfter(timeToNextEffect - s_minimumDelay);
+
+ ASSERT(!hasOutdatedAnimationPlayer());
+}
+
+void AnimationTimeline::AnimationTimelineTiming::wakeAfter(double duration)
+{
+ m_timer.startOneShot(duration, FROM_HERE);
+}
+
+void AnimationTimeline::AnimationTimelineTiming::cancelWake()
+{
+ m_timer.stop();
+}
+
+void AnimationTimeline::AnimationTimelineTiming::serviceOnNextFrame()
+{
+ if (m_timeline->m_document && m_timeline->m_document->view())
+ m_timeline->m_document->view()->scheduleAnimation();
+}
+
+void AnimationTimeline::AnimationTimelineTiming::trace(Visitor* visitor)
+{
+ visitor->trace(m_timeline);
+ AnimationTimeline::PlatformTiming::trace(visitor);
+}
+
+double AnimationTimeline::currentTime(bool& isNull)
+{
+ return currentTimeInternal(isNull) * 1000;
+}
+
+double AnimationTimeline::currentTimeInternal(bool& isNull)
+{
+ if (!m_document) {
+ isNull = true;
+ return std::numeric_limits<double>::quiet_NaN();
+ }
+ double result = m_document->animationClock().currentTime() - zeroTime();
+ isNull = std::isnan(result);
+ return result;
+}
+
+double AnimationTimeline::currentTime()
+{
+ return currentTimeInternal() * 1000;
+}
+
+double AnimationTimeline::currentTimeInternal()
+{
+ bool isNull;
+ return currentTimeInternal(isNull);
+}
+
+double AnimationTimeline::effectiveTime()
+{
+ double time = currentTimeInternal();
+ return std::isnan(time) ? 0 : time;
+}
+
+void AnimationTimeline::pauseAnimationsForTesting(double pauseTime)
+{
+ for (WillBeHeapHashSet<RefPtrWillBeMember<AnimationPlayer> >::iterator it = m_playersNeedingUpdate.begin(); it != m_playersNeedingUpdate.end(); ++it)
+ (*it)->pauseForTesting(pauseTime);
+ serviceAnimations(TimingUpdateOnDemand);
+}
+
+bool AnimationTimeline::hasOutdatedAnimationPlayer() const
+{
+ for (WillBeHeapHashSet<RefPtrWillBeMember<AnimationPlayer> >::iterator it = m_playersNeedingUpdate.begin(); it != m_playersNeedingUpdate.end(); ++it) {
+ if ((*it)->outdated())
+ return true;
+ }
+ return false;
+}
+
+void AnimationTimeline::setOutdatedAnimationPlayer(AnimationPlayer* player)
+{
+ ASSERT(player->outdated());
+ m_playersNeedingUpdate.add(player);
+ if (m_document && m_document->page() && !m_document->page()->animator().isServicingAnimations())
+ m_timing->serviceOnNextFrame();
+}
+
+size_t AnimationTimeline::numberOfActiveAnimationsForTesting() const
+{
+ // Includes all players whose directly associated timed items
+ // are current or in effect.
+ size_t count = 0;
+ for (WillBeHeapHashSet<RefPtrWillBeMember<AnimationPlayer> >::iterator it = m_playersNeedingUpdate.begin(); it != m_playersNeedingUpdate.end(); ++it) {
+ const AnimationNode* animationNode = (*it)->source();
+ if ((*it)->hasStartTime())
+ count += (animationNode && (animationNode->isCurrent() || animationNode->isInEffect()));
+ }
+ return count;
+}
+
+#if !ENABLE(OILPAN)
+void AnimationTimeline::detachFromDocument()
+{
+ // FIXME: AnimationTimeline should keep Document alive.
+ m_document = nullptr;
+}
+#endif
+
+void AnimationTimeline::trace(Visitor* visitor)
+{
+ visitor->trace(m_document);
+ visitor->trace(m_timing);
+ visitor->trace(m_playersNeedingUpdate);
+ visitor->trace(m_players);
+}
+
+} // namespace
diff --git a/chromium/third_party/WebKit/Source/core/animation/DocumentTimeline.h b/chromium/third_party/WebKit/Source/core/animation/AnimationTimeline.h
index 2bf58f852c6..1a523a28651 100644
--- a/chromium/third_party/WebKit/Source/core/animation/DocumentTimeline.h
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimationTimeline.h
@@ -28,14 +28,15 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef DocumentTimeline_h
-#define DocumentTimeline_h
+#ifndef AnimationTimeline_h
+#define AnimationTimeline_h
#include "core/animation/AnimationEffect.h"
-#include "core/animation/Player.h"
+#include "core/animation/AnimationPlayer.h"
#include "core/dom/Element.h"
#include "core/events/Event.h"
#include "platform/Timer.h"
+#include "platform/heap/Handle.h"
#include "wtf/RefCounted.h"
#include "wtf/RefPtr.h"
#include "wtf/Vector.h"
@@ -43,80 +44,80 @@
namespace WebCore {
class Document;
-class TimedItem;
+class AnimationNode;
-// DocumentTimeline is constructed and owned by Document, and tied to its lifecycle.
-class DocumentTimeline : public RefCounted<DocumentTimeline> {
+// AnimationTimeline is constructed and owned by Document, and tied to its lifecycle.
+class AnimationTimeline : public RefCountedWillBeGarbageCollectedFinalized<AnimationTimeline> {
public:
- class PlatformTiming {
+ class PlatformTiming : public NoBaseWillBeGarbageCollectedFinalized<PlatformTiming> {
public:
- // Calls DocumentTimeline's wake() method after duration seconds.
+ // Calls AnimationTimeline's wake() method after duration seconds.
virtual void wakeAfter(double duration) = 0;
virtual void cancelWake() = 0;
virtual void serviceOnNextFrame() = 0;
virtual ~PlatformTiming() { }
-
+ virtual void trace(Visitor*) { }
};
- static PassRefPtr<DocumentTimeline> create(Document*, PassOwnPtr<PlatformTiming> = nullptr);
- // Returns whether style recalc was triggered.
- bool serviceAnimations();
+ static PassRefPtrWillBeRawPtr<AnimationTimeline> create(Document*, PassOwnPtrWillBeRawPtr<PlatformTiming> = nullptr);
+ ~AnimationTimeline();
+
+ void serviceAnimations(TimingUpdateReason);
// Creates a player attached to this timeline, but without a start time.
- Player* createPlayer(TimedItem*);
- Player* play(TimedItem*);
-
- // Called from setReadyState() in Document.cpp to set m_zeroTime to
- // performance.timing.domInteractive
- void setZeroTime(double);
- bool hasStarted() const { return !isNull(m_zeroTime); }
- double zeroTime() const { return m_zeroTime; }
+ AnimationPlayer* createAnimationPlayer(AnimationNode*);
+ AnimationPlayer* play(AnimationNode*);
+
+#if !ENABLE(OILPAN)
+ void playerDestroyed(AnimationPlayer* player)
+ {
+ ASSERT(m_players.contains(player));
+ m_players.remove(player);
+ }
+#endif
+
+ bool hasPendingUpdates() const { return !m_playersNeedingUpdate.isEmpty(); }
+ double zeroTime() const { return 0; }
+ double currentTime(bool& isNull);
double currentTime();
+ double currentTimeInternal(bool& isNull);
+ double currentTimeInternal();
+ double effectiveTime();
void pauseAnimationsForTesting(double);
size_t numberOfActiveAnimationsForTesting() const;
- const Vector<RefPtr<Player> >& players() const { return m_players; }
- void addEventToDispatch(EventTarget* target, PassRefPtr<Event> event)
- {
- m_events.append(EventToDispatch(target, event));
- }
+ void setOutdatedAnimationPlayer(AnimationPlayer*);
+ bool hasOutdatedAnimationPlayer() const;
+
+ Document* document() { return m_document.get(); }
+#if !ENABLE(OILPAN)
+ void detachFromDocument();
+#endif
+ void wake();
- void dispatchEvents();
- void dispatchEventsAsync();
+ void trace(Visitor*);
protected:
- DocumentTimeline(Document*, PassOwnPtr<PlatformTiming>);
+ AnimationTimeline(Document*, PassOwnPtrWillBeRawPtr<PlatformTiming>);
private:
- double m_zeroTime;
- Document* m_document;
- Timer<DocumentTimeline> m_eventDistpachTimer;
- Vector<RefPtr<Player> > m_players;
-
- void eventDispatchTimerFired(Timer<DocumentTimeline>*);
- void wake();
-
- struct EventToDispatch {
- EventToDispatch(EventTarget* target, PassRefPtr<Event> event)
- : target(target)
- , event(event)
- {
- }
- RefPtr<EventTarget> target;
- RefPtr<Event> event;
- };
- Vector<EventToDispatch> m_events;
+ RawPtrWillBeMember<Document> m_document;
+ // AnimationPlayers which will be updated on the next frame
+ // i.e. current, in effect, or had timing changed
+ WillBeHeapHashSet<RefPtrWillBeMember<AnimationPlayer> > m_playersNeedingUpdate;
+ WillBeHeapHashSet<RawPtrWillBeWeakMember<AnimationPlayer> > m_players;
+ friend class SMILTimeContainer;
static const double s_minimumDelay;
- OwnPtr<PlatformTiming> m_timing;
+ OwnPtrWillBeMember<PlatformTiming> m_timing;
- class DocumentTimelineTiming : public PlatformTiming {
+ class AnimationTimelineTiming FINAL : public PlatformTiming {
public:
- DocumentTimelineTiming(DocumentTimeline* documentTimeline)
- : m_timeline(documentTimeline)
- , m_timer(this, &DocumentTimelineTiming::timerFired)
+ AnimationTimelineTiming(AnimationTimeline* timeline)
+ : m_timeline(timeline)
+ , m_timer(this, &AnimationTimelineTiming::timerFired)
{
ASSERT(m_timeline);
}
@@ -125,15 +126,16 @@ private:
virtual void cancelWake() OVERRIDE;
virtual void serviceOnNextFrame() OVERRIDE;
- void timerFired(Timer<DocumentTimelineTiming>*) { m_timeline->wake(); }
+ void timerFired(Timer<AnimationTimelineTiming>*) { m_timeline->wake(); }
- private:
- DocumentTimeline* m_timeline;
- Timer<DocumentTimelineTiming> m_timer;
+ virtual void trace(Visitor*) OVERRIDE;
+ private:
+ RawPtrWillBeMember<AnimationTimeline> m_timeline;
+ Timer<AnimationTimelineTiming> m_timer;
};
- friend class AnimationDocumentTimelineTest;
+ friend class AnimationAnimationTimelineTest;
};
} // namespace
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimationTimeline.idl b/chromium/third_party/WebKit/Source/core/animation/AnimationTimeline.idl
new file mode 100644
index 00000000000..b2c627afde3
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimationTimeline.idl
@@ -0,0 +1,11 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+[
+ RuntimeEnabled=WebAnimationsAPI,
+ WillBeGarbageCollected,
+] interface AnimationTimeline {
+ readonly attribute double? currentTime;
+ AnimationPlayer play(AnimationNode source);
+};
diff --git a/chromium/third_party/WebKit/Source/core/animation/DocumentTimelineTest.cpp b/chromium/third_party/WebKit/Source/core/animation/AnimationTimelineTest.cpp
index 41fad8ce2c4..68cc2895a9b 100644
--- a/chromium/third_party/WebKit/Source/core/animation/DocumentTimelineTest.cpp
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimationTimelineTest.cpp
@@ -29,12 +29,12 @@
*/
#include "config.h"
-#include "core/animation/DocumentTimeline.h"
+#include "core/animation/AnimationTimeline.h"
#include "core/animation/Animation.h"
#include "core/animation/AnimationClock.h"
-#include "core/animation/KeyframeAnimationEffect.h"
-#include "core/animation/TimedItem.h"
+#include "core/animation/AnimationNode.h"
+#include "core/animation/KeyframeEffectModel.h"
#include "core/dom/Document.h"
#include "core/dom/Element.h"
#include "core/dom/QualifiedName.h"
@@ -45,7 +45,7 @@
namespace WebCore {
-class MockPlatformTiming : public DocumentTimeline::PlatformTiming {
+class MockPlatformTiming : public AnimationTimeline::PlatformTiming {
public:
MOCK_METHOD1(wakeAfter, void(double));
@@ -53,7 +53,7 @@ public:
MOCK_METHOD0(serviceOnNextFrame, void());
/**
- * DocumentTimelines should do one of the following things after servicing animations:
+ * AnimationTimelines should do one of the following things after servicing animations:
* - cancel the timer and not request to be woken again (expectNoMoreActions)
* - cancel the timer and request to be woken on the next frame (expectNextFrameAction)
* - cancel the timer and request to be woken at some point in the future (expectDelayedAction)
@@ -77,37 +77,41 @@ public:
EXPECT_CALL(*this, cancelWake()).InSequence(sequence);
EXPECT_CALL(*this, wakeAfter(when)).InSequence(sequence);
}
+
+ void trace(Visitor* visitor)
+ {
+ AnimationTimeline::PlatformTiming::trace(visitor);
+ }
};
-class AnimationDocumentTimelineTest : public ::testing::Test {
+class AnimationAnimationTimelineTest : public ::testing::Test {
protected:
virtual void SetUp()
{
document = Document::create();
document->animationClock().resetTimeForTesting();
- element = Element::create(nullQName() , document.get());
+ element = Element::create(QualifiedName::null() , document.get());
platformTiming = new MockPlatformTiming;
- timeline = DocumentTimeline::create(document.get(), adoptPtr(platformTiming));
- timeline->setZeroTime(0);
- ASSERT_EQ(0, timeline->currentTime());
+ timeline = AnimationTimeline::create(document.get(), adoptPtrWillBeNoop(platformTiming));
+ ASSERT_EQ(0, timeline->currentTimeInternal());
}
virtual void TearDown()
{
- timeline.release();
document.release();
element.release();
+ timeline.release();
}
void updateClockAndService(double time)
{
document->animationClock().updateTime(time);
- timeline->serviceAnimations();
+ timeline->serviceAnimations(TimingUpdateForAnimationFrame);
}
- RefPtr<Document> document;
- RefPtr<Element> element;
- RefPtr<DocumentTimeline> timeline;
+ RefPtrWillBePersistent<Document> document;
+ RefPtrWillBePersistent<Element> element;
+ RefPtrWillBePersistent<AnimationTimeline> timeline;
Timing timing;
MockPlatformTiming* platformTiming;
@@ -118,155 +122,135 @@ protected:
double minimumDelay()
{
- return DocumentTimeline::s_minimumDelay;
+ return AnimationTimeline::s_minimumDelay;
}
};
-TEST_F(AnimationDocumentTimelineTest, HasStarted)
+TEST_F(AnimationAnimationTimelineTest, HasStarted)
{
- timeline = DocumentTimeline::create(document.get());
- EXPECT_FALSE(timeline->hasStarted());
- timeline->setZeroTime(0);
- EXPECT_TRUE(timeline->hasStarted());
+ timeline = AnimationTimeline::create(document.get());
}
-TEST_F(AnimationDocumentTimelineTest, EmptyKeyframeAnimation)
+TEST_F(AnimationAnimationTimelineTest, EmptyKeyframeAnimation)
{
- RefPtr<KeyframeAnimationEffect> effect = KeyframeAnimationEffect::create(KeyframeAnimationEffect::KeyframeVector());
- RefPtr<Animation> anim = Animation::create(element.get(), effect, timing);
+ RefPtrWillBeRawPtr<AnimatableValueKeyframeEffectModel> effect = AnimatableValueKeyframeEffectModel::create(AnimatableValueKeyframeVector());
+ RefPtrWillBeRawPtr<Animation> anim = Animation::create(element.get(), effect, timing);
timeline->play(anim.get());
platformTiming->expectNoMoreActions();
updateClockAndService(0);
- EXPECT_FLOAT_EQ(0, timeline->currentTime());
- EXPECT_TRUE(anim->compositableValues()->isEmpty());
+ EXPECT_FLOAT_EQ(0, timeline->currentTimeInternal());
+ EXPECT_FALSE(anim->isInEffect());
platformTiming->expectNoMoreActions();
updateClockAndService(100);
- EXPECT_FLOAT_EQ(100, timeline->currentTime());
+ EXPECT_FLOAT_EQ(100, timeline->currentTimeInternal());
}
-TEST_F(AnimationDocumentTimelineTest, EmptyTimelineDoesNotTriggerStyleRecalc)
+TEST_F(AnimationAnimationTimelineTest, EmptyForwardsKeyframeAnimation)
{
- document->animationClock().updateTime(100);
- EXPECT_FALSE(timeline->serviceAnimations());
-}
+ RefPtrWillBeRawPtr<AnimatableValueKeyframeEffectModel> effect = AnimatableValueKeyframeEffectModel::create(AnimatableValueKeyframeVector());
+ timing.fillMode = Timing::FillModeForwards;
+ RefPtrWillBeRawPtr<Animation> anim = Animation::create(element.get(), effect, timing);
-TEST_F(AnimationDocumentTimelineTest, EmptyPlayerDoesNotTriggerStyleRecalc)
-{
- timeline->play(0);
- document->animationClock().updateTime(100);
- EXPECT_FALSE(timeline->serviceAnimations());
-}
-
-TEST_F(AnimationDocumentTimelineTest, EmptyTargetDoesNotTriggerStyleRecalc)
-{
- timing.iterationDuration = 200;
- timeline->play(Animation::create(0, KeyframeAnimationEffect::create(KeyframeAnimationEffect::KeyframeVector()), timing).get());
- document->animationClock().updateTime(100);
- EXPECT_FALSE(timeline->serviceAnimations());
-}
+ timeline->play(anim.get());
-TEST_F(AnimationDocumentTimelineTest, EmptyEffectDoesNotTriggerStyleRecalc)
-{
- timeline->play(Animation::create(element.get(), 0, timing).get());
- document->animationClock().updateTime(100);
- EXPECT_FALSE(timeline->serviceAnimations());
-}
+ platformTiming->expectNoMoreActions();
+ updateClockAndService(0);
+ EXPECT_FLOAT_EQ(0, timeline->currentTimeInternal());
+ EXPECT_TRUE(anim->isInEffect());
-TEST_F(AnimationDocumentTimelineTest, TriggerStyleRecalc)
-{
- timeline->play(Animation::create(element.get(), KeyframeAnimationEffect::create(KeyframeAnimationEffect::KeyframeVector()), timing).get());
- document->animationClock().updateTime(100);
- EXPECT_TRUE(timeline->serviceAnimations());
+ platformTiming->expectNoMoreActions();
+ updateClockAndService(100);
+ EXPECT_FLOAT_EQ(100, timeline->currentTimeInternal());
}
-TEST_F(AnimationDocumentTimelineTest, ZeroTime)
+TEST_F(AnimationAnimationTimelineTest, ZeroTime)
{
- timeline = DocumentTimeline::create(document.get());
+ timeline = AnimationTimeline::create(document.get());
+ bool isNull;
document->animationClock().updateTime(100);
- EXPECT_TRUE(isNull(timeline->currentTime()));
+ EXPECT_EQ(100, timeline->currentTimeInternal());
+ EXPECT_EQ(100, timeline->currentTimeInternal(isNull));
+ EXPECT_FALSE(isNull);
document->animationClock().updateTime(200);
- EXPECT_TRUE(isNull(timeline->currentTime()));
-
- timeline->setZeroTime(300);
- document->animationClock().updateTime(300);
- EXPECT_EQ(0, timeline->currentTime());
-
- document->animationClock().updateTime(400);
- EXPECT_EQ(100, timeline->currentTime());
+ EXPECT_EQ(200, timeline->currentTimeInternal());
+ EXPECT_EQ(200, timeline->currentTimeInternal(isNull));
+ EXPECT_FALSE(isNull);
}
-TEST_F(AnimationDocumentTimelineTest, PauseForTesting)
+TEST_F(AnimationAnimationTimelineTest, PauseForTesting)
{
float seekTime = 1;
- RefPtr<Animation> anim1 = Animation::create(element.get(), KeyframeAnimationEffect::create(KeyframeAnimationEffect::KeyframeVector()), timing);
- RefPtr<Animation> anim2 = Animation::create(element.get(), KeyframeAnimationEffect::create(KeyframeAnimationEffect::KeyframeVector()), timing);
- Player* player1 = timeline->play(anim1.get());
- Player* player2 = timeline->play(anim2.get());
+ timing.fillMode = Timing::FillModeForwards;
+ RefPtrWillBeRawPtr<Animation> anim1 = Animation::create(element.get(), AnimatableValueKeyframeEffectModel::create(AnimatableValueKeyframeVector()), timing);
+ RefPtrWillBeRawPtr<Animation> anim2 = Animation::create(element.get(), AnimatableValueKeyframeEffectModel::create(AnimatableValueKeyframeVector()), timing);
+ AnimationPlayer* player1 = timeline->play(anim1.get());
+ AnimationPlayer* player2 = timeline->play(anim2.get());
timeline->pauseAnimationsForTesting(seekTime);
- EXPECT_FLOAT_EQ(seekTime, player1->currentTime());
- EXPECT_FLOAT_EQ(seekTime, player2->currentTime());
+ EXPECT_FLOAT_EQ(seekTime, player1->currentTimeInternal());
+ EXPECT_FLOAT_EQ(seekTime, player2->currentTimeInternal());
}
-TEST_F(AnimationDocumentTimelineTest, NumberOfActiveAnimations)
+TEST_F(AnimationAnimationTimelineTest, NumberOfActiveAnimations)
{
Timing timingForwardFill;
- timingForwardFill.hasIterationDuration = true;
timingForwardFill.iterationDuration = 2;
+ timingForwardFill.fillMode = Timing::FillModeForwards;
Timing timingNoFill;
- timingNoFill.hasIterationDuration = true;
timingNoFill.iterationDuration = 2;
timingNoFill.fillMode = Timing::FillModeNone;
Timing timingBackwardFillDelay;
- timingBackwardFillDelay.hasIterationDuration = true;
timingBackwardFillDelay.iterationDuration = 1;
timingBackwardFillDelay.fillMode = Timing::FillModeBackwards;
timingBackwardFillDelay.startDelay = 1;
Timing timingNoFillDelay;
- timingNoFillDelay.hasIterationDuration = true;
timingNoFillDelay.iterationDuration = 1;
timingNoFillDelay.fillMode = Timing::FillModeNone;
timingNoFillDelay.startDelay = 1;
- RefPtr<Animation> anim1 = Animation::create(element.get(), KeyframeAnimationEffect::create(KeyframeAnimationEffect::KeyframeVector()), timingForwardFill);
- RefPtr<Animation> anim2 = Animation::create(element.get(), KeyframeAnimationEffect::create(KeyframeAnimationEffect::KeyframeVector()), timingNoFill);
- RefPtr<Animation> anim3 = Animation::create(element.get(), KeyframeAnimationEffect::create(KeyframeAnimationEffect::KeyframeVector()), timingBackwardFillDelay);
- RefPtr<Animation> anim4 = Animation::create(element.get(), KeyframeAnimationEffect::create(KeyframeAnimationEffect::KeyframeVector()), timingNoFillDelay);
+ Timing timingAutoFill;
+ timingAutoFill.iterationDuration = 2;
+
+ RefPtrWillBeRawPtr<Animation> anim1 = Animation::create(element.get(), AnimatableValueKeyframeEffectModel::create(AnimatableValueKeyframeVector()), timingForwardFill);
+ RefPtrWillBeRawPtr<Animation> anim2 = Animation::create(element.get(), AnimatableValueKeyframeEffectModel::create(AnimatableValueKeyframeVector()), timingNoFill);
+ RefPtrWillBeRawPtr<Animation> anim3 = Animation::create(element.get(), AnimatableValueKeyframeEffectModel::create(AnimatableValueKeyframeVector()), timingBackwardFillDelay);
+ RefPtrWillBeRawPtr<Animation> anim4 = Animation::create(element.get(), AnimatableValueKeyframeEffectModel::create(AnimatableValueKeyframeVector()), timingNoFillDelay);
+ RefPtrWillBeRawPtr<Animation> anim5 = Animation::create(element.get(), AnimatableValueKeyframeEffectModel::create(AnimatableValueKeyframeVector()), timingAutoFill);
timeline->play(anim1.get());
timeline->play(anim2.get());
timeline->play(anim3.get());
timeline->play(anim4.get());
+ timeline->play(anim5.get());
platformTiming->expectNextFrameAction();
updateClockAndService(0);
- EXPECT_EQ(4U, timeline->numberOfActiveAnimationsForTesting());
+ EXPECT_EQ(5U, timeline->numberOfActiveAnimationsForTesting());
platformTiming->expectNextFrameAction();
updateClockAndService(0.5);
- EXPECT_EQ(4U, timeline->numberOfActiveAnimationsForTesting());
+ EXPECT_EQ(5U, timeline->numberOfActiveAnimationsForTesting());
platformTiming->expectNextFrameAction();
updateClockAndService(1.5);
- EXPECT_EQ(4U, timeline->numberOfActiveAnimationsForTesting());
+ EXPECT_EQ(5U, timeline->numberOfActiveAnimationsForTesting());
platformTiming->expectNoMoreActions();
updateClockAndService(3);
- EXPECT_EQ(1U, timeline->numberOfActiveAnimationsForTesting());
+ EXPECT_EQ(0U, timeline->numberOfActiveAnimationsForTesting());
}
-TEST_F(AnimationDocumentTimelineTest, DelayBeforeAnimationStart)
+TEST_F(AnimationAnimationTimelineTest, DelayBeforeAnimationStart)
{
- timing.hasIterationDuration = true;
timing.iterationDuration = 2;
timing.startDelay = 5;
- RefPtr<Animation> anim = Animation::create(element.get(), 0, timing);
+ RefPtrWillBeRawPtr<Animation> anim = Animation::create(element.get(), nullptr, timing);
timeline->play(anim.get());
@@ -284,4 +268,26 @@ TEST_F(AnimationDocumentTimelineTest, DelayBeforeAnimationStart)
updateClockAndService(4.98);
}
+TEST_F(AnimationAnimationTimelineTest, PlayAfterDocumentDeref)
+{
+ timing.iterationDuration = 2;
+ timing.startDelay = 5;
+
+ timeline = &document->timeline();
+ element = nullptr;
+ document = nullptr;
+
+ RefPtrWillBeRawPtr<Animation> anim = Animation::create(0, nullptr, timing);
+ // Test passes if this does not crash.
+ timeline->play(anim.get());
+}
+
+TEST_F(AnimationAnimationTimelineTest, UseAnimationPlayerAfterTimelineDeref)
+{
+ RefPtrWillBeRawPtr<AnimationPlayer> player = timeline->createAnimationPlayer(0);
+ timeline.clear();
+ // Test passes if this does not crash.
+ player->setStartTime(0);
+}
+
}
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimationTranslationUtil.cpp b/chromium/third_party/WebKit/Source/core/animation/AnimationTranslationUtil.cpp
new file mode 100644
index 00000000000..3fbdf306611
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimationTranslationUtil.cpp
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2012 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "core/animation/AnimationTranslationUtil.h"
+
+#include "platform/graphics/filters/FilterOperations.h"
+#include "platform/graphics/filters/SkiaImageFilterBuilder.h"
+#include "platform/transforms/InterpolatedTransformOperation.h"
+#include "platform/transforms/Matrix3DTransformOperation.h"
+#include "platform/transforms/MatrixTransformOperation.h"
+#include "platform/transforms/PerspectiveTransformOperation.h"
+#include "platform/transforms/RotateTransformOperation.h"
+#include "platform/transforms/ScaleTransformOperation.h"
+#include "platform/transforms/SkewTransformOperation.h"
+#include "platform/transforms/TransformOperations.h"
+#include "platform/transforms/TransformationMatrix.h"
+#include "platform/transforms/TranslateTransformOperation.h"
+#include "public/platform/WebTransformOperations.h"
+
+using namespace blink;
+
+namespace WebCore {
+
+void toWebTransformOperations(const TransformOperations& transformOperations, WebTransformOperations* webTransformOperations)
+{
+ // We need to do a deep copy the transformOperations may contain ref pointers to TransformOperation objects.
+ for (size_t j = 0; j < transformOperations.size(); ++j) {
+ switch (transformOperations.operations()[j]->type()) {
+ case TransformOperation::ScaleX:
+ case TransformOperation::ScaleY:
+ case TransformOperation::ScaleZ:
+ case TransformOperation::Scale3D:
+ case TransformOperation::Scale: {
+ ScaleTransformOperation* transform = static_cast<ScaleTransformOperation*>(transformOperations.operations()[j].get());
+ webTransformOperations->appendScale(transform->x(), transform->y(), transform->z());
+ break;
+ }
+ case TransformOperation::TranslateX:
+ case TransformOperation::TranslateY:
+ case TransformOperation::TranslateZ:
+ case TransformOperation::Translate3D:
+ case TransformOperation::Translate: {
+ TranslateTransformOperation* transform = static_cast<TranslateTransformOperation*>(transformOperations.operations()[j].get());
+ ASSERT(transform->x().isFixed() && transform->y().isFixed());
+ webTransformOperations->appendTranslate(transform->x().value(), transform->y().value(), transform->z());
+ break;
+ }
+ case TransformOperation::RotateX:
+ case TransformOperation::RotateY:
+ case TransformOperation::Rotate3D:
+ case TransformOperation::Rotate: {
+ RotateTransformOperation* transform = static_cast<RotateTransformOperation*>(transformOperations.operations()[j].get());
+ webTransformOperations->appendRotate(transform->x(), transform->y(), transform->z(), transform->angle());
+ break;
+ }
+ case TransformOperation::SkewX:
+ case TransformOperation::SkewY:
+ case TransformOperation::Skew: {
+ SkewTransformOperation* transform = static_cast<SkewTransformOperation*>(transformOperations.operations()[j].get());
+ webTransformOperations->appendSkew(transform->angleX(), transform->angleY());
+ break;
+ }
+ case TransformOperation::Matrix: {
+ MatrixTransformOperation* transform = static_cast<MatrixTransformOperation*>(transformOperations.operations()[j].get());
+ TransformationMatrix m = transform->matrix();
+ webTransformOperations->appendMatrix(TransformationMatrix::toSkMatrix44(m));
+ break;
+ }
+ case TransformOperation::Matrix3D: {
+ Matrix3DTransformOperation* transform = static_cast<Matrix3DTransformOperation*>(transformOperations.operations()[j].get());
+ TransformationMatrix m = transform->matrix();
+ webTransformOperations->appendMatrix(TransformationMatrix::toSkMatrix44(m));
+ break;
+ }
+ case TransformOperation::Perspective: {
+ PerspectiveTransformOperation* transform = static_cast<PerspectiveTransformOperation*>(transformOperations.operations()[j].get());
+ webTransformOperations->appendPerspective(transform->perspective());
+ break;
+ }
+ case TransformOperation::Interpolated: {
+ TransformationMatrix m;
+ transformOperations.operations()[j]->apply(m, FloatSize());
+ webTransformOperations->appendMatrix(TransformationMatrix::toSkMatrix44(m));
+ break;
+ }
+ case TransformOperation::Identity:
+ webTransformOperations->appendIdentity();
+ break;
+ case TransformOperation::None:
+ // Do nothing.
+ break;
+ } // switch
+ } // for each operation
+}
+
+bool toWebFilterOperations(const FilterOperations& inOperations, WebFilterOperations* outOperations)
+{
+ SkiaImageFilterBuilder builder;
+ FilterOutsets outsets = inOperations.outsets();
+ builder.setCropOffset(FloatSize(outsets.left(), outsets.top()));
+ return builder.buildFilterOperations(inOperations, outOperations);
+}
+
+} // namespace WebCore
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimationTranslationUtil.h b/chromium/third_party/WebKit/Source/core/animation/AnimationTranslationUtil.h
new file mode 100644
index 00000000000..c69635b5200
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimationTranslationUtil.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef AnimationTranslationUtil_h
+#define AnimationTranslationUtil_h
+
+namespace blink {
+class WebTransformOperations;
+class WebFilterOperations;
+}
+
+namespace WebCore {
+
+class FilterOperations;
+class TransformOperations;
+
+void toWebTransformOperations(const TransformOperations& inOperations, blink::WebTransformOperations* outOperations);
+bool toWebFilterOperations(const FilterOperations& inOperations, blink::WebFilterOperations* outOperations);
+
+} // namespace WebCore
+
+#endif // AnimationTranslationUtil_h
diff --git a/chromium/third_party/WebKit/Source/core/animation/AnimationTranslationUtilTest.cpp b/chromium/third_party/WebKit/Source/core/animation/AnimationTranslationUtilTest.cpp
new file mode 100644
index 00000000000..d55e790d2af
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/AnimationTranslationUtilTest.cpp
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2012 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "core/animation/AnimationTranslationUtil.h"
+
+#include "core/animation/css/CSSAnimationData.h"
+#include "platform/animation/KeyframeValueList.h"
+#include "platform/geometry/IntSize.h"
+#include "platform/graphics/filters/FilterOperations.h"
+#include "platform/transforms/Matrix3DTransformOperation.h"
+#include "platform/transforms/RotateTransformOperation.h"
+#include "platform/transforms/ScaleTransformOperation.h"
+#include "platform/transforms/TransformOperations.h"
+#include "platform/transforms/TranslateTransformOperation.h"
+#include "public/platform/WebAnimation.h"
+#include "public/platform/WebFilterOperations.h"
+#include "public/platform/WebTransformOperations.h"
+#include "wtf/RefPtr.h"
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+using namespace WebCore;
+using namespace blink;
+
+namespace {
+
+class WebTransformOperationsMock : public blink::WebTransformOperations {
+public:
+ MOCK_CONST_METHOD1(canBlendWith, bool(const WebTransformOperations&));
+ MOCK_METHOD3(appendTranslate, void(double, double, double));
+ MOCK_METHOD4(appendRotate, void(double, double, double, double));
+ MOCK_METHOD3(appendScale, void(double, double, double));
+ MOCK_METHOD2(appendSkew, void(double, double));
+ MOCK_METHOD1(appendPerspective, void(double));
+ MOCK_METHOD1(appendMatrix, void(const SkMatrix44&));
+ MOCK_METHOD0(appendIdentity, void());
+ MOCK_CONST_METHOD0(isIdentity, bool());
+};
+
+class WebFilterOperationsMock : public blink::WebFilterOperations {
+public:
+ MOCK_METHOD1(appendGrayscaleFilter, void(float));
+ MOCK_METHOD1(appendSepiaFilter, void(float));
+ MOCK_METHOD1(appendSaturateFilter, void(float));
+ MOCK_METHOD1(appendHueRotateFilter, void(float));
+ MOCK_METHOD1(appendInvertFilter, void(float));
+ MOCK_METHOD1(appendBrightnessFilter, void(float));
+ MOCK_METHOD1(appendContrastFilter, void(float));
+ MOCK_METHOD1(appendOpacityFilter, void(float));
+ MOCK_METHOD1(appendBlurFilter, void(float));
+ MOCK_METHOD3(appendDropShadowFilter, void(WebPoint, float, WebColor));
+ MOCK_METHOD1(appendColorMatrixFilter, void(SkScalar[20]));
+ MOCK_METHOD2(appendZoomFilter, void(float, int));
+ MOCK_METHOD1(appendSaturatingBrightnessFilter, void(float));
+ MOCK_METHOD1(appendReferenceFilter, void(SkImageFilter*));
+ MOCK_METHOD0(clear, void());
+};
+
+TEST(AnimationTranslationUtilTest, transformsWork)
+{
+ TransformOperations ops;
+ WebTransformOperationsMock outOps;
+
+ EXPECT_CALL(outOps, appendTranslate(2, 0, 0));
+ EXPECT_CALL(outOps, appendRotate(0.1, 0.2, 0.3, 200000.4));
+ EXPECT_CALL(outOps, appendScale(50.2, 100, -4));
+
+ ops.operations().append(TranslateTransformOperation::create(Length(2, WebCore::Fixed), Length(0, WebCore::Fixed), TransformOperation::TranslateX));
+ ops.operations().append(RotateTransformOperation::create(0.1, 0.2, 0.3, 200000.4, TransformOperation::Rotate3D));
+ ops.operations().append(ScaleTransformOperation::create(50.2, 100, -4, TransformOperation::Scale3D));
+ toWebTransformOperations(ops, &outOps);
+}
+
+TEST(AnimationTranslationUtilTest, filtersWork)
+{
+ FilterOperations ops;
+ WebFilterOperationsMock outOps;
+
+ EXPECT_CALL(outOps, appendSaturateFilter(0.5));
+ EXPECT_CALL(outOps, appendGrayscaleFilter(0.2f));
+ EXPECT_CALL(outOps, appendSepiaFilter(0.8f));
+ EXPECT_CALL(outOps, appendOpacityFilter(0.1f));
+
+ ops.operations().append(BasicColorMatrixFilterOperation::create(0.5, FilterOperation::SATURATE));
+ ops.operations().append(BasicColorMatrixFilterOperation::create(0.2, FilterOperation::GRAYSCALE));
+ ops.operations().append(BasicColorMatrixFilterOperation::create(0.8, FilterOperation::SEPIA));
+ ops.operations().append(BasicColorMatrixFilterOperation::create(0.1, FilterOperation::OPACITY));
+ toWebFilterOperations(ops, &outOps);
+}
+
+}
+
diff --git a/chromium/third_party/WebKit/Source/core/animation/CompositorAnimations.cpp b/chromium/third_party/WebKit/Source/core/animation/CompositorAnimations.cpp
index 929f0737165..f2128db3b61 100644
--- a/chromium/third_party/WebKit/Source/core/animation/CompositorAnimations.cpp
+++ b/chromium/third_party/WebKit/Source/core/animation/CompositorAnimations.cpp
@@ -35,12 +35,12 @@
#include "core/animation/AnimatableFilterOperations.h"
#include "core/animation/AnimatableTransform.h"
#include "core/animation/AnimatableValue.h"
+#include "core/animation/AnimationTranslationUtil.h"
#include "core/animation/CompositorAnimationsImpl.h"
-#include "core/platform/animation/AnimationTranslationUtil.h"
-#include "core/rendering/CompositedLayerMapping.h"
#include "core/rendering/RenderBoxModelObject.h"
#include "core/rendering/RenderLayer.h"
#include "core/rendering/RenderObject.h"
+#include "core/rendering/compositing/CompositedLayerMapping.h"
#include "public/platform/Platform.h"
#include "public/platform/WebAnimation.h"
#include "public/platform/WebCompositorSupport.h"
@@ -58,10 +58,10 @@ namespace WebCore {
namespace {
-void getKeyframeValuesForProperty(const KeyframeAnimationEffect* effect, CSSPropertyID id, double scale, bool reverse, KeyframeVector& values)
+void getKeyframeValuesForProperty(const KeyframeEffectModelBase* effect, CSSPropertyID id, double scale, bool reverse, PropertySpecificKeyframeVector& values)
{
ASSERT(values.isEmpty());
- const KeyframeVector& group = effect->getPropertySpecificKeyframes(id);
+ const PropertySpecificKeyframeVector& group = effect->getPropertySpecificKeyframes(id);
if (reverse) {
for (size_t i = group.size(); i--;) {
@@ -105,18 +105,6 @@ PassRefPtr<TimingFunction> CompositorAnimationsTimingFunctionReverser::reverse(c
}
}
-PassRefPtr<TimingFunction> CompositorAnimationsTimingFunctionReverser::reverse(const ChainedTimingFunction* timefunc)
-{
- RefPtr<ChainedTimingFunction> reversed = ChainedTimingFunction::create();
- for (size_t i = 0; i < timefunc->m_segments.size(); i++) {
- size_t index = timefunc->m_segments.size() - i - 1;
-
- RefPtr<TimingFunction> rtf = reverse(timefunc->m_segments[index].m_timingFunction.get());
- reversed->appendSegment(1 - timefunc->m_segments[index].m_min, rtf.get());
- }
- return reversed;
-}
-
PassRefPtr<TimingFunction> CompositorAnimationsTimingFunctionReverser::reverse(const TimingFunction* timefunc)
{
switch (timefunc->type()) {
@@ -128,10 +116,6 @@ PassRefPtr<TimingFunction> CompositorAnimationsTimingFunctionReverser::reverse(c
const CubicBezierTimingFunction* cubic = toCubicBezierTimingFunction(timefunc);
return reverse(cubic);
}
- case TimingFunction::ChainedFunction: {
- const ChainedTimingFunction* chained = toChainedTimingFunction(timefunc);
- return reverse(chained);
- }
// Steps function can not be reversed.
case TimingFunction::StepsFunction:
@@ -147,103 +131,54 @@ PassRefPtr<TimingFunction> CompositorAnimationsTimingFunctionReverser::reverse(c
bool CompositorAnimations::isCandidateForAnimationOnCompositor(const Timing& timing, const AnimationEffect& effect)
{
- const KeyframeAnimationEffect& keyframeEffect = *toKeyframeAnimationEffect(&effect);
+ const KeyframeEffectModelBase& keyframeEffect = *toKeyframeEffectModelBase(&effect);
- // Are the keyframes convertible?
- const KeyframeAnimationEffect::KeyframeVector frames = keyframeEffect.getFrames();
- for (size_t i = 0; i < frames.size(); ++i) {
- // Only replace mode can be accelerated
- if (frames[i]->composite() != AnimationEffect::CompositeReplace)
- return false;
+ PropertySet properties = keyframeEffect.properties();
- // Check all the properties can be accelerated
- const PropertySet properties = frames[i]->properties(); // FIXME: properties creates a whole new PropertySet!
+ if (properties.isEmpty())
+ return false;
- if (properties.isEmpty())
- return false;
+ for (PropertySet::const_iterator it = properties.begin(); it != properties.end(); ++it) {
+ const PropertySpecificKeyframeVector& frames = keyframeEffect.getPropertySpecificKeyframes(*it);
+ ASSERT(frames.size() >= 2);
+ for (size_t i = 0; i < frames.size(); ++i) {
+ const Keyframe::PropertySpecificKeyframe *frame = frames[i].get();
+ // FIXME: Determine candidacy based on the CSSValue instead of a snapshot AnimatableValue.
+ if (frame->composite() != AnimationEffect::CompositeReplace || !frame->getAnimatableValue())
+ return false;
- for (PropertySet::const_iterator it = properties.begin(); it != properties.end(); ++it) {
switch (*it) {
case CSSPropertyOpacity:
- continue;
- case CSSPropertyWebkitTransform:
- if (toAnimatableTransform(frames[i]->propertyValue(CSSPropertyWebkitTransform))->transformOperations().dependsOnBoxSize())
+ break;
+ case CSSPropertyTransform:
+ if (toAnimatableTransform(frame->getAnimatableValue().get())->transformOperations().dependsOnBoxSize())
return false;
- continue;
+ break;
case CSSPropertyWebkitFilter: {
- const FilterOperations& operations = toAnimatableFilterOperations(frames[i]->propertyValue(CSSPropertyWebkitFilter))->operations();
+ const FilterOperations& operations = toAnimatableFilterOperations(frame->getAnimatableValue().get())->operations();
if (operations.hasFilterThatMovesPixels())
return false;
- for (size_t i = 0; i < operations.size(); i++) {
- const FilterOperation& op = *operations.at(i);
- if (op.type() == FilterOperation::VALIDATED_CUSTOM || op.type() == FilterOperation::CUSTOM)
- return false;
- }
- continue;
+ break;
}
default:
return false;
}
+
+ // FIXME: Remove this check when crbug.com/229405 is resolved
+ if (i < frames.size() - 1 && frame->easing()->type() == TimingFunction::StepsFunction)
+ return false;
}
}
- // Is the timing object convertible?
CompositorAnimationsImpl::CompositorTiming out;
if (!CompositorAnimationsImpl::convertTimingForCompositor(timing, out))
return false;
- // Is the timing function convertible?
- switch (timing.timingFunction->type()) {
- case TimingFunction::LinearFunction:
- break;
-
- case TimingFunction::CubicBezierFunction:
- // Can have a cubic if we don't have to split it (IE only have two frames).
- if (frames.size() != 2)
- return false;
-
- ASSERT(frames[0]->offset() == 0.0 && frames[1]->offset() == 1.0);
- break;
-
- case TimingFunction::StepsFunction:
+ // FIXME: We should support non-linear timing functions in the compositor
+ // eventually.
+ if (timing.timingFunction->type() != TimingFunction::LinearFunction)
return false;
- case TimingFunction::ChainedFunction: {
- // Currently we only support chained segments in the form the CSS code
- // generates. These chained segments are only one level deep and have
- // one timing function per frame.
- const ChainedTimingFunction* chained = static_cast<const ChainedTimingFunction*>(timing.timingFunction.get());
- if (!chained->m_segments.size())
- return false;
-
- if (frames.size() != chained->m_segments.size() + 1)
- return false;
-
- for (size_t timeIndex = 0; timeIndex < chained->m_segments.size(); timeIndex++) {
- const ChainedTimingFunction::Segment& segment = chained->m_segments[timeIndex];
-
- if (frames[timeIndex]->offset() != segment.m_min || frames[timeIndex + 1]->offset() != segment.m_max)
- return false;
-
- switch (segment.m_timingFunction->type()) {
- case TimingFunction::LinearFunction:
- case TimingFunction::CubicBezierFunction:
- continue;
-
- case TimingFunction::StepsFunction:
- case TimingFunction::ChainedFunction:
- default:
- return false;
- }
- }
-
- break;
- }
- default:
- ASSERT_NOT_REACHED();
- return false;
- }
-
return true;
}
@@ -252,19 +187,19 @@ bool CompositorAnimations::canStartAnimationOnCompositor(const Element& element)
return element.renderer() && element.renderer()->compositingState() == PaintsIntoOwnBacking;
}
-bool CompositorAnimations::startAnimationOnCompositor(const Element& element, const Timing& timing, const AnimationEffect& effect, Vector<int>& startedAnimationIds)
+bool CompositorAnimations::startAnimationOnCompositor(const Element& element, double startTime, const Timing& timing, const AnimationEffect& effect, Vector<int>& startedAnimationIds)
{
ASSERT(startedAnimationIds.isEmpty());
ASSERT(isCandidateForAnimationOnCompositor(timing, effect));
ASSERT(canStartAnimationOnCompositor(element));
- const KeyframeAnimationEffect& keyframeEffect = *toKeyframeAnimationEffect(&effect);
+ const KeyframeEffectModelBase& keyframeEffect = *toKeyframeEffectModelBase(&effect);
RenderLayer* layer = toRenderBoxModelObject(element.renderer())->layer();
ASSERT(layer);
Vector<OwnPtr<blink::WebAnimation> > animations;
- CompositorAnimationsImpl::getAnimationOnCompositor(timing, keyframeEffect, animations);
+ CompositorAnimationsImpl::getAnimationOnCompositor(timing, startTime, keyframeEffect, animations);
ASSERT(!animations.isEmpty());
for (size_t i = 0; i < animations.size(); ++i) {
int id = animations[i]->id();
@@ -284,7 +219,11 @@ bool CompositorAnimations::startAnimationOnCompositor(const Element& element, co
void CompositorAnimations::cancelAnimationOnCompositor(const Element& element, int id)
{
if (!canStartAnimationOnCompositor(element)) {
- ASSERT_NOT_REACHED();
+ // When an element is being detached, we cancel any associated
+ // AnimationPlayers for CSS animations. But by the time we get
+ // here the mapping will have been removed.
+ // FIXME: Defer remove/pause operations until after the
+ // compositing update.
return;
}
toRenderBoxModelObject(element.renderer())->layer()->compositedLayerMapping()->mainGraphicsLayer()->removeAnimation(id);
@@ -292,6 +231,10 @@ void CompositorAnimations::cancelAnimationOnCompositor(const Element& element, i
void CompositorAnimations::pauseAnimationForTestingOnCompositor(const Element& element, int id, double pauseTime)
{
+ // FIXME: canStartAnimationOnCompositor queries compositingState, which is not necessarily up to date.
+ // https://code.google.com/p/chromium/issues/detail?id=339847
+ DisableCompositingQueryAsserts disabler;
+
if (!canStartAnimationOnCompositor(element)) {
ASSERT_NOT_REACHED();
return;
@@ -318,7 +261,7 @@ bool CompositorAnimationsImpl::convertTimingForCompositor(const Timing& timing,
if ((std::floor(timing.iterationCount) != timing.iterationCount) || timing.iterationCount <= 0)
return false;
- if (!timing.iterationDuration)
+ if (std::isnan(timing.iterationDuration) || !timing.iterationDuration)
return false;
// FIXME: Support other playback rates
@@ -402,7 +345,6 @@ void addKeyframeWithTimingFunction(PlatformAnimationCurveType& curve, const Plat
}
case TimingFunction::StepsFunction:
- case TimingFunction::ChainedFunction:
default:
ASSERT_NOT_REACHED();
return;
@@ -411,39 +353,29 @@ void addKeyframeWithTimingFunction(PlatformAnimationCurveType& curve, const Plat
} // namespace anoymous
-void CompositorAnimationsImpl::addKeyframesToCurve(blink::WebAnimationCurve& curve, const KeyframeVector& keyframes, const TimingFunction& timingFunction)
+void CompositorAnimationsImpl::addKeyframesToCurve(blink::WebAnimationCurve& curve, const PropertySpecificKeyframeVector& keyframes, bool reverse)
{
for (size_t i = 0; i < keyframes.size(); i++) {
+ RefPtr<TimingFunction> reversedTimingFunction;
const TimingFunction* keyframeTimingFunction = 0;
- if (i + 1 < keyframes.size()) { // Last keyframe has no timing function
- switch (timingFunction.type()) {
- case TimingFunction::LinearFunction:
- case TimingFunction::CubicBezierFunction:
- keyframeTimingFunction = &timingFunction;
- break;
-
- case TimingFunction::ChainedFunction: {
- const ChainedTimingFunction& chained = toChainedTimingFunction(timingFunction);
- // ChainedTimingFunction criteria was checked in isCandidate,
- // assert it is valid.
- ASSERT(keyframes.size() == chained.m_segments.size() + 1);
-
- keyframeTimingFunction = chained.m_segments[i].m_timingFunction.get();
- break;
- }
- case TimingFunction::StepsFunction:
- default:
- ASSERT_NOT_REACHED();
+ if (i < keyframes.size() - 1) { // Ignore timing function of last frame.
+ if (reverse) {
+ reversedTimingFunction = CompositorAnimationsTimingFunctionReverser::reverse(keyframes[i + 1]->easing());
+ keyframeTimingFunction = reversedTimingFunction.get();
+ } else {
+ keyframeTimingFunction = keyframes[i]->easing();
}
}
- ASSERT(!keyframes[i]->value()->dependsOnUnderlyingValue());
- RefPtr<AnimatableValue> value = keyframes[i]->value()->compositeOnto(0);
+ // FIXME: This relies on StringKeyframes being eagerly evaluated, which will
+ // not happen eventually. Instead we should extract the CSSValue here
+ // and convert using another set of toAnimatableXXXOperations functions.
+ const AnimatableValue* value = keyframes[i]->getAnimatableValue().get();
switch (curve.type()) {
case blink::WebAnimationCurve::AnimationCurveTypeFilter: {
OwnPtr<blink::WebFilterOperations> ops = adoptPtr(blink::Platform::current()->compositorSupport()->createFilterOperations());
- bool converted = toWebFilterOperations(toAnimatableFilterOperations(value.get())->operations(), ops.get());
+ bool converted = toWebFilterOperations(toAnimatableFilterOperations(value)->operations(), ops.get());
ASSERT_UNUSED(converted, converted);
blink::WebFilterKeyframe filterKeyframe(keyframes[i]->offset(), ops.release());
@@ -452,14 +384,14 @@ void CompositorAnimationsImpl::addKeyframesToCurve(blink::WebAnimationCurve& cur
break;
}
case blink::WebAnimationCurve::AnimationCurveTypeFloat: {
- blink::WebFloatKeyframe floatKeyframe(keyframes[i]->offset(), toAnimatableDouble(value.get())->toDouble());
+ blink::WebFloatKeyframe floatKeyframe(keyframes[i]->offset(), toAnimatableDouble(value)->toDouble());
blink::WebFloatAnimationCurve* floatCurve = static_cast<blink::WebFloatAnimationCurve*>(&curve);
addKeyframeWithTimingFunction(*floatCurve, floatKeyframe, keyframeTimingFunction);
break;
}
case blink::WebAnimationCurve::AnimationCurveTypeTransform: {
OwnPtr<blink::WebTransformOperations> ops = adoptPtr(blink::Platform::current()->compositorSupport()->createTransformOperations());
- toWebTransformOperations(toAnimatableTransform(value.get())->transformOperations(), FloatSize(), ops.get());
+ toWebTransformOperations(toAnimatableTransform(value)->transformOperations(), ops.get());
blink::WebTransformKeyframe transformKeyframe(keyframes[i]->offset(), ops.release());
blink::WebTransformAnimationCurve* transformCurve = static_cast<blink::WebTransformAnimationCurve*>(&curve);
@@ -472,23 +404,18 @@ void CompositorAnimationsImpl::addKeyframesToCurve(blink::WebAnimationCurve& cur
}
}
-void CompositorAnimationsImpl::getAnimationOnCompositor(
- const Timing& timing, const KeyframeAnimationEffect& effect, Vector<OwnPtr<blink::WebAnimation> >& animations)
+void CompositorAnimationsImpl::getAnimationOnCompositor(const Timing& timing, double startTime, const KeyframeEffectModelBase& effect, Vector<OwnPtr<blink::WebAnimation> >& animations)
{
ASSERT(animations.isEmpty());
CompositorTiming compositorTiming;
bool timingValid = convertTimingForCompositor(timing, compositorTiming);
ASSERT_UNUSED(timingValid, timingValid);
- RefPtr<TimingFunction> timingFunction = timing.timingFunction;
- if (compositorTiming.reverse)
- timingFunction = CompositorAnimationsTimingFunctionReverser::reverse(timingFunction.get());
-
PropertySet properties = effect.properties();
ASSERT(!properties.isEmpty());
for (PropertySet::iterator it = properties.begin(); it != properties.end(); ++it) {
- KeyframeVector values;
+ PropertySpecificKeyframeVector values;
getKeyframeValuesForProperty(&effect, *it, compositorTiming.scaledDuration, compositorTiming.reverse, values);
blink::WebAnimation::TargetProperty targetProperty;
@@ -498,21 +425,21 @@ void CompositorAnimationsImpl::getAnimationOnCompositor(
targetProperty = blink::WebAnimation::TargetPropertyOpacity;
blink::WebFloatAnimationCurve* floatCurve = blink::Platform::current()->compositorSupport()->createFloatAnimationCurve();
- addKeyframesToCurve(*floatCurve, values, *timingFunction.get());
+ addKeyframesToCurve(*floatCurve, values, compositorTiming.reverse);
curve = adoptPtr(floatCurve);
break;
}
case CSSPropertyWebkitFilter: {
targetProperty = blink::WebAnimation::TargetPropertyFilter;
blink::WebFilterAnimationCurve* filterCurve = blink::Platform::current()->compositorSupport()->createFilterAnimationCurve();
- addKeyframesToCurve(*filterCurve, values, *timingFunction);
+ addKeyframesToCurve(*filterCurve, values, compositorTiming.reverse);
curve = adoptPtr(filterCurve);
break;
}
- case CSSPropertyWebkitTransform: {
+ case CSSPropertyTransform: {
targetProperty = blink::WebAnimation::TargetPropertyTransform;
blink::WebTransformAnimationCurve* transformCurve = blink::Platform::current()->compositorSupport()->createTransformAnimationCurve();
- addKeyframesToCurve(*transformCurve, values, *timingFunction.get());
+ addKeyframesToCurve(*transformCurve, values, compositorTiming.reverse);
curve = adoptPtr(transformCurve);
break;
}
@@ -524,6 +451,9 @@ void CompositorAnimationsImpl::getAnimationOnCompositor(
OwnPtr<blink::WebAnimation> animation = adoptPtr(blink::Platform::current()->compositorSupport()->createAnimation(*curve, targetProperty));
+ if (!std::isnan(startTime))
+ animation->setStartTime(startTime);
+
animation->setIterations(compositorTiming.adjustedIterationCount);
animation->setTimeOffset(compositorTiming.scaledTimeOffset);
animation->setAlternatesDirection(compositorTiming.alternate);
diff --git a/chromium/third_party/WebKit/Source/core/animation/CompositorAnimations.h b/chromium/third_party/WebKit/Source/core/animation/CompositorAnimations.h
index 9a529731fa0..da2cf497de2 100644
--- a/chromium/third_party/WebKit/Source/core/animation/CompositorAnimations.h
+++ b/chromium/third_party/WebKit/Source/core/animation/CompositorAnimations.h
@@ -33,7 +33,7 @@
#include "core/animation/AnimationEffect.h"
#include "core/animation/Timing.h"
-#include "core/platform/animation/TimingFunction.h"
+#include "platform/animation/TimingFunction.h"
#include "wtf/Vector.h"
namespace WebCore {
@@ -49,7 +49,6 @@ class CompositorAnimationsTimingFunctionReverser {
public:
static PassRefPtr<TimingFunction> reverse(const LinearTimingFunction* timefunc);
static PassRefPtr<TimingFunction> reverse(const CubicBezierTimingFunction* timefunc);
- static PassRefPtr<TimingFunction> reverse(const ChainedTimingFunction* timefunc);
static PassRefPtr<TimingFunction> reverse(const TimingFunction* timefunc);
};
@@ -61,7 +60,7 @@ public:
virtual bool isCandidateForAnimationOnCompositor(const Timing&, const AnimationEffect&);
virtual bool canStartAnimationOnCompositor(const Element&);
// FIXME: This should return void. We should know ahead of time whether these animations can be started.
- virtual bool startAnimationOnCompositor(const Element&, const Timing&, const AnimationEffect&, Vector<int>& startedAnimationIds);
+ virtual bool startAnimationOnCompositor(const Element&, double startTime, const Timing&, const AnimationEffect&, Vector<int>& startedAnimationIds);
virtual void cancelAnimationOnCompositor(const Element&, int id);
virtual void pauseAnimationForTestingOnCompositor(const Element&, int id, double pauseTime);
diff --git a/chromium/third_party/WebKit/Source/core/animation/CompositorAnimationsImpl.h b/chromium/third_party/WebKit/Source/core/animation/CompositorAnimationsImpl.h
index 7c32705f23b..d2f06f5b81c 100644
--- a/chromium/third_party/WebKit/Source/core/animation/CompositorAnimationsImpl.h
+++ b/chromium/third_party/WebKit/Source/core/animation/CompositorAnimationsImpl.h
@@ -29,15 +29,13 @@
*/
#include "core/animation/AnimationEffect.h"
-#include "core/animation/KeyframeAnimationEffect.h"
+#include "core/animation/KeyframeEffectModel.h"
#include "core/animation/Timing.h"
-#include "core/platform/animation/TimingFunction.h"
+#include "platform/animation/TimingFunction.h"
#include "public/platform/WebAnimation.h"
namespace WebCore {
-typedef KeyframeAnimationEffect::PropertySpecificKeyframeVector KeyframeVector;
-
class CompositorAnimationsImpl {
private:
struct CompositorTiming {
@@ -50,9 +48,9 @@ private:
static bool convertTimingForCompositor(const Timing&, CompositorTiming& out);
- static void getAnimationOnCompositor(const Timing&, const KeyframeAnimationEffect&, Vector<OwnPtr<blink::WebAnimation> >& animations);
+ static void getAnimationOnCompositor(const Timing&, double startTime, const KeyframeEffectModelBase&, Vector<OwnPtr<blink::WebAnimation> >& animations);
- static void addKeyframesToCurve(blink::WebAnimationCurve&, const KeyframeVector&, const TimingFunction&);
+ static void addKeyframesToCurve(blink::WebAnimationCurve&, const AnimatableValuePropertySpecificKeyframeVector&, bool reverse);
friend class CompositorAnimations;
friend class AnimationCompositorAnimationsTest;
diff --git a/chromium/third_party/WebKit/Source/core/animation/CompositorAnimationsTest.cpp b/chromium/third_party/WebKit/Source/core/animation/CompositorAnimationsTest.cpp
index db0d9a6c4bd..ad88c352261 100644
--- a/chromium/third_party/WebKit/Source/core/animation/CompositorAnimationsTest.cpp
+++ b/chromium/third_party/WebKit/Source/core/animation/CompositorAnimationsTest.cpp
@@ -38,7 +38,6 @@
#include "core/animation/AnimatableValueTestHelper.h"
#include "core/animation/CompositorAnimationsImpl.h"
#include "core/animation/CompositorAnimationsTestHelper.h"
-#include "core/platform/animation/TimingFunctionTestHelper.h"
#include "platform/geometry/IntSize.h"
#include "platform/graphics/filters/FilterOperations.h"
#include "platform/transforms/TransformOperations.h"
@@ -62,7 +61,6 @@ using ::testing::Return;
using ::testing::_;
class AnimationCompositorAnimationsTest : public AnimationCompositorAnimationsTestBase {
-
protected:
RefPtr<TimingFunction> m_linearTimingFunction;
RefPtr<TimingFunction> m_cubicEaseTimingFunction;
@@ -71,19 +69,19 @@ protected:
Timing m_timing;
CompositorAnimationsImpl::CompositorTiming m_compositorTiming;
- KeyframeAnimationEffect::KeyframeVector m_keyframeVector2;
- RefPtr<KeyframeAnimationEffect> m_keyframeAnimationEffect2;
- KeyframeAnimationEffect::KeyframeVector m_keyframeVector5;
- RefPtr<KeyframeAnimationEffect> m_keyframeAnimationEffect5;
+ OwnPtrWillBePersistent<AnimatableValueKeyframeVector> m_keyframeVector2;
+ RefPtrWillBePersistent<AnimatableValueKeyframeEffectModel> m_keyframeAnimationEffect2;
+ OwnPtrWillBePersistent<AnimatableValueKeyframeVector> m_keyframeVector5;
+ RefPtrWillBePersistent<AnimatableValueKeyframeEffectModel> m_keyframeAnimationEffect5;
virtual void SetUp()
{
AnimationCompositorAnimationsTestBase::SetUp();
- m_linearTimingFunction = LinearTimingFunction::create();
+ m_linearTimingFunction = LinearTimingFunction::shared();
m_cubicEaseTimingFunction = CubicBezierTimingFunction::preset(CubicBezierTimingFunction::Ease);
m_cubicCustomTimingFunction = CubicBezierTimingFunction::create(1, 2, 3, 4);
- m_stepTimingFunction = StepsTimingFunction::create(1, false);
+ m_stepTimingFunction = StepsTimingFunction::create(1, StepsTimingFunction::StepAtEnd);
m_timing = createCompositableTiming();
m_compositorTiming = CompositorAnimationsImpl::CompositorTiming();
@@ -92,10 +90,10 @@ protected:
ASSERT(convertTimingForCompositor(m_timing, m_compositorTiming));
m_keyframeVector2 = createCompositableFloatKeyframeVector(2);
- m_keyframeAnimationEffect2 = KeyframeAnimationEffect::create(m_keyframeVector2);
+ m_keyframeAnimationEffect2 = AnimatableValueKeyframeEffectModel::create(*m_keyframeVector2);
m_keyframeVector5 = createCompositableFloatKeyframeVector(5);
- m_keyframeAnimationEffect5 = KeyframeAnimationEffect::create(m_keyframeVector5);
+ m_keyframeAnimationEffect5 = AnimatableValueKeyframeEffectModel::create(*m_keyframeVector5);
}
public:
@@ -108,19 +106,20 @@ public:
{
return CompositorAnimations::instance()->isCandidateForAnimationOnCompositor(timing, effect);
}
- void getAnimationOnCompositor(Timing& timing, KeyframeAnimationEffect& effect, Vector<OwnPtr<blink::WebAnimation> >& animations)
+ void getAnimationOnCompositor(Timing& timing, AnimatableValueKeyframeEffectModel& effect, Vector<OwnPtr<blink::WebAnimation> >& animations)
{
- return CompositorAnimationsImpl::getAnimationOnCompositor(timing, effect, animations);
+ return CompositorAnimationsImpl::getAnimationOnCompositor(timing, std::numeric_limits<double>::quiet_NaN(), effect, animations);
}
- bool isCandidateHelperForSingleKeyframe(Keyframe* frame)
+ bool duplicateSingleKeyframeAndTestIsCandidateOnResult(AnimatableValueKeyframe* frame)
{
EXPECT_EQ(frame->offset(), 0);
- KeyframeAnimationEffect::KeyframeVector frames;
+ AnimatableValueKeyframeVector frames;
+ RefPtrWillBeRawPtr<Keyframe> second = frame->cloneWithOffset(1);
+
frames.append(frame);
- EXPECT_EQ(m_keyframeVector2[1]->offset(), 1.0);
- frames.append(m_keyframeVector2[1]);
- return isCandidateForAnimationOnCompositor(m_timing, *KeyframeAnimationEffect::create(frames).get());
+ frames.append(toAnimatableValueKeyframe(second.get()));
+ return isCandidateForAnimationOnCompositor(m_timing, *AnimatableValueKeyframeEffectModel::create(frames).get());
}
// -------------------------------------------------------------------
@@ -132,7 +131,6 @@ public:
timing.fillMode = Timing::FillModeNone;
timing.iterationStart = 0;
timing.iterationCount = 1;
- timing.hasIterationDuration = true;
timing.iterationDuration = 1.0;
timing.playbackRate = 1.0;
timing.direction = Timing::PlaybackDirectionNormal;
@@ -141,29 +139,30 @@ public:
return timing;
}
- PassRefPtr<Keyframe> createReplaceOpKeyframe(CSSPropertyID id, AnimatableValue* value, double offset = 0)
+ PassRefPtrWillBeRawPtr<AnimatableValueKeyframe> createReplaceOpKeyframe(CSSPropertyID id, AnimatableValue* value, double offset = 0)
{
- RefPtr<Keyframe> keyframe = Keyframe::create();
+ RefPtrWillBeRawPtr<AnimatableValueKeyframe> keyframe = AnimatableValueKeyframe::create();
keyframe->setPropertyValue(id, value);
keyframe->setComposite(AnimationEffect::CompositeReplace);
keyframe->setOffset(offset);
+ keyframe->setEasing(LinearTimingFunction::shared());
return keyframe;
}
- PassRefPtr<Keyframe> createDefaultKeyframe(CSSPropertyID id, AnimationEffect::CompositeOperation op, double offset = 0)
+ PassRefPtrWillBeRawPtr<AnimatableValueKeyframe> createDefaultKeyframe(CSSPropertyID id, AnimationEffect::CompositeOperation op, double offset = 0)
{
- RefPtr<AnimatableValue> value;
- if (id == CSSPropertyWebkitTransform)
+ RefPtrWillBeRawPtr<AnimatableValue> value = nullptr;
+ if (id == CSSPropertyTransform)
value = AnimatableTransform::create(TransformOperations());
else
value = AnimatableDouble::create(10.0);
- RefPtr<Keyframe> keyframe = createReplaceOpKeyframe(id, value.get(), offset);
+ RefPtrWillBeRawPtr<AnimatableValueKeyframe> keyframe = createReplaceOpKeyframe(id, value.get(), offset);
keyframe->setComposite(op);
return keyframe;
}
- KeyframeAnimationEffect::KeyframeVector createCompositableFloatKeyframeVector(size_t n)
+ PassOwnPtrWillBeRawPtr<AnimatableValueKeyframeVector> createCompositableFloatKeyframeVector(size_t n)
{
Vector<double> values;
for (size_t i = 0; i < n; i++) {
@@ -172,26 +171,26 @@ public:
return createCompositableFloatKeyframeVector(values);
}
- KeyframeAnimationEffect::KeyframeVector createCompositableFloatKeyframeVector(Vector<double>& values)
+ PassOwnPtrWillBeRawPtr<AnimatableValueKeyframeVector> createCompositableFloatKeyframeVector(Vector<double>& values)
{
- KeyframeAnimationEffect::KeyframeVector frames;
+ OwnPtrWillBeRawPtr<AnimatableValueKeyframeVector> frames = adoptPtrWillBeNoop(new AnimatableValueKeyframeVector);
for (size_t i = 0; i < values.size(); i++) {
double offset = 1.0 / (values.size() - 1) * i;
- RefPtr<AnimatableDouble> value = AnimatableDouble::create(values[i]);
- frames.append(createReplaceOpKeyframe(CSSPropertyOpacity, value.get(), offset).get());
+ RefPtrWillBeRawPtr<AnimatableDouble> value = AnimatableDouble::create(values[i]);
+ frames->append(createReplaceOpKeyframe(CSSPropertyOpacity, value.get(), offset).get());
}
- return frames;
+ return frames.release();
}
- PassRefPtr<KeyframeAnimationEffect> createKeyframeAnimationEffect(PassRefPtr<Keyframe> prpFrom, PassRefPtr<Keyframe> prpTo, PassRefPtr<Keyframe> prpC = 0, PassRefPtr<Keyframe> prpD = 0)
+ PassRefPtrWillBeRawPtr<AnimatableValueKeyframeEffectModel> createKeyframeEffectModel(PassRefPtrWillBeRawPtr<AnimatableValueKeyframe> prpFrom, PassRefPtrWillBeRawPtr<AnimatableValueKeyframe> prpTo, PassRefPtrWillBeRawPtr<AnimatableValueKeyframe> prpC = nullptr, PassRefPtrWillBeRawPtr<AnimatableValueKeyframe> prpD = nullptr)
{
- RefPtr<Keyframe> from = prpFrom;
- RefPtr<Keyframe> to = prpTo;
- RefPtr<Keyframe> c = prpC;
- RefPtr<Keyframe> d = prpD;
+ RefPtrWillBeRawPtr<AnimatableValueKeyframe> from = prpFrom;
+ RefPtrWillBeRawPtr<AnimatableValueKeyframe> to = prpTo;
+ RefPtrWillBeRawPtr<AnimatableValueKeyframe> c = prpC;
+ RefPtrWillBeRawPtr<AnimatableValueKeyframe> d = prpD;
EXPECT_EQ(from->offset(), 0);
- KeyframeAnimationEffect::KeyframeVector frames;
+ AnimatableValueKeyframeVector frames;
frames.append(from);
EXPECT_LE(from->offset(), to->offset());
frames.append(to);
@@ -207,31 +206,11 @@ public:
EXPECT_EQ(to->offset(), 1.0);
}
if (!HasFatalFailure()) {
- return KeyframeAnimationEffect::create(frames);
+ return AnimatableValueKeyframeEffectModel::create(frames);
}
- return PassRefPtr<KeyframeAnimationEffect>();
- }
-
-};
-
-class CustomFilterOperationMock : public FilterOperation {
-public:
- virtual bool operator==(const FilterOperation&) const OVERRIDE FINAL {
- ASSERT_NOT_REACHED();
- return false;
- }
-
- MOCK_CONST_METHOD2(blend, PassRefPtr<FilterOperation>(const FilterOperation*, double));
-
- static PassRefPtr<CustomFilterOperationMock> create()
- {
- return adoptRef(new CustomFilterOperationMock());
+ return nullptr;
}
- CustomFilterOperationMock()
- : FilterOperation(FilterOperation::CUSTOM)
- {
- }
};
// -----------------------------------------------------------------------
@@ -239,88 +218,57 @@ public:
TEST_F(AnimationCompositorAnimationsTest, isCandidateForAnimationOnCompositorKeyframeMultipleCSSProperties)
{
- RefPtr<Keyframe> keyframeGoodMultiple = createDefaultKeyframe(CSSPropertyOpacity, AnimationEffect::CompositeReplace);
- keyframeGoodMultiple->setPropertyValue(CSSPropertyWebkitTransform, AnimatableTransform::create(TransformOperations()).get());
- EXPECT_TRUE(isCandidateHelperForSingleKeyframe(keyframeGoodMultiple.get()));
-
- RefPtr<Keyframe> keyframeBadMultipleOp = createDefaultKeyframe(CSSPropertyOpacity, AnimationEffect::CompositeAdd);
- keyframeBadMultipleOp->setPropertyValue(CSSPropertyWebkitTransform, AnimatableDouble::create(10.0).get());
- EXPECT_FALSE(isCandidateHelperForSingleKeyframe(keyframeBadMultipleOp.get()));
-
- // Check both an unsupported property which hashes before and after the
- // supported property.
- typedef DefaultHash<CSSPropertyID>::Hash HashFunctions;
-
- RefPtr<Keyframe> keyframeBadMultiple1ID = createDefaultKeyframe(CSSPropertyColor, AnimationEffect::CompositeReplace);
- keyframeBadMultiple1ID->setPropertyValue(CSSPropertyOpacity, AnimatableDouble::create(10.0).get());
- EXPECT_FALSE(isCandidateHelperForSingleKeyframe(keyframeBadMultiple1ID.get()));
- EXPECT_LT(HashFunctions::hash(CSSPropertyColor), HashFunctions::hash(CSSPropertyOpacity));
-
- RefPtr<Keyframe> keyframeBadMultiple2ID = createDefaultKeyframe(CSSPropertyWebkitTransform, AnimationEffect::CompositeReplace);
- keyframeBadMultiple2ID->setPropertyValue(CSSPropertyWidth, AnimatableDouble::create(10.0).get());
- EXPECT_FALSE(isCandidateHelperForSingleKeyframe(keyframeBadMultiple2ID.get()));
- EXPECT_GT(HashFunctions::hash(CSSPropertyWebkitTransform), HashFunctions::hash(CSSPropertyWidth));
+ RefPtrWillBeRawPtr<AnimatableValueKeyframe> keyframeGoodMultiple = createDefaultKeyframe(CSSPropertyOpacity, AnimationEffect::CompositeReplace);
+ keyframeGoodMultiple->setPropertyValue(CSSPropertyTransform, AnimatableTransform::create(TransformOperations()).get());
+ EXPECT_TRUE(duplicateSingleKeyframeAndTestIsCandidateOnResult(keyframeGoodMultiple.get()));
+
+ RefPtrWillBeRawPtr<AnimatableValueKeyframe> keyframeBadMultipleID = createDefaultKeyframe(CSSPropertyColor, AnimationEffect::CompositeReplace);
+ keyframeBadMultipleID->setPropertyValue(CSSPropertyOpacity, AnimatableDouble::create(10.0).get());
+ EXPECT_FALSE(duplicateSingleKeyframeAndTestIsCandidateOnResult(keyframeBadMultipleID.get()));
}
TEST_F(AnimationCompositorAnimationsTest, isNotCandidateForCompositorAnimationTransformDependsOnBoxSize)
{
TransformOperations ops;
ops.operations().append(TranslateTransformOperation::create(Length(2, WebCore::Fixed), Length(2, WebCore::Fixed), TransformOperation::TranslateX));
- RefPtr<Keyframe> goodKeyframe = createReplaceOpKeyframe(CSSPropertyWebkitTransform, AnimatableTransform::create(ops).get());
- EXPECT_TRUE(isCandidateHelperForSingleKeyframe(goodKeyframe.get()));
+ RefPtrWillBeRawPtr<AnimatableValueKeyframe> goodKeyframe = createReplaceOpKeyframe(CSSPropertyTransform, AnimatableTransform::create(ops).get());
+ EXPECT_TRUE(duplicateSingleKeyframeAndTestIsCandidateOnResult(goodKeyframe.get()));
ops.operations().append(TranslateTransformOperation::create(Length(50, WebCore::Percent), Length(2, WebCore::Fixed), TransformOperation::TranslateX));
- RefPtr<Keyframe> badKeyframe = createReplaceOpKeyframe(CSSPropertyWebkitTransform, AnimatableTransform::create(ops).get());
- EXPECT_FALSE(isCandidateHelperForSingleKeyframe(badKeyframe.get()));
+ RefPtrWillBeRawPtr<AnimatableValueKeyframe> badKeyframe = createReplaceOpKeyframe(CSSPropertyTransform, AnimatableTransform::create(ops).get());
+ EXPECT_FALSE(duplicateSingleKeyframeAndTestIsCandidateOnResult(badKeyframe.get()));
TransformOperations ops2;
Length calcLength = Length(100, WebCore::Percent).blend(Length(100, WebCore::Fixed), 0.5, WebCore::ValueRangeAll);
ops2.operations().append(TranslateTransformOperation::create(calcLength, Length(0, WebCore::Fixed), TransformOperation::TranslateX));
- RefPtr<Keyframe> badKeyframe2 = createReplaceOpKeyframe(CSSPropertyWebkitTransform, AnimatableTransform::create(ops2).get());
- EXPECT_FALSE(isCandidateHelperForSingleKeyframe(badKeyframe2.get()));
-}
-
-TEST_F(AnimationCompositorAnimationsTest, isNotCandidateForCompositorAnimationCustomFilter)
-{
- FilterOperations ops;
- ops.operations().append(BasicColorMatrixFilterOperation::create(0.5, FilterOperation::SATURATE));
- RefPtr<Keyframe> goodKeyframe = createReplaceOpKeyframe(CSSPropertyWebkitFilter, AnimatableFilterOperations::create(ops).get());
- EXPECT_TRUE(isCandidateHelperForSingleKeyframe(goodKeyframe.get()));
-
- ops.operations().append(CustomFilterOperationMock::create());
- RefPtr<Keyframe> badKeyframe = createReplaceOpKeyframe(CSSPropertyFilter, AnimatableFilterOperations::create(ops).get());
- EXPECT_FALSE(isCandidateHelperForSingleKeyframe(badKeyframe.get()));
+ RefPtrWillBeRawPtr<AnimatableValueKeyframe> badKeyframe2 = createReplaceOpKeyframe(CSSPropertyTransform, AnimatableTransform::create(ops2).get());
+ EXPECT_FALSE(duplicateSingleKeyframeAndTestIsCandidateOnResult(badKeyframe2.get()));
}
-TEST_F(AnimationCompositorAnimationsTest, isCandidateForAnimationOnCompositorKeyframeEffectMultipleFramesOkay)
+TEST_F(AnimationCompositorAnimationsTest, isCandidateForAnimationOnCompositorKeyframeEffectModelMultipleFramesOkay)
{
- KeyframeAnimationEffect::KeyframeVector framesSame;
+ AnimatableValueKeyframeVector framesSame;
framesSame.append(createDefaultKeyframe(CSSPropertyOpacity, AnimationEffect::CompositeReplace, 0.0).get());
framesSame.append(createDefaultKeyframe(CSSPropertyOpacity, AnimationEffect::CompositeReplace, 1.0).get());
- EXPECT_TRUE(isCandidateForAnimationOnCompositor(m_timing, *KeyframeAnimationEffect::create(framesSame).get()));
+ EXPECT_TRUE(isCandidateForAnimationOnCompositor(m_timing, *AnimatableValueKeyframeEffectModel::create(framesSame).get()));
- KeyframeAnimationEffect::KeyframeVector framesMixed;
+ AnimatableValueKeyframeVector framesMixed;
framesMixed.append(createDefaultKeyframe(CSSPropertyOpacity, AnimationEffect::CompositeReplace, 0.0).get());
- framesMixed.append(createDefaultKeyframe(CSSPropertyWebkitTransform, AnimationEffect::CompositeReplace, 1.0).get());
- EXPECT_TRUE(isCandidateForAnimationOnCompositor(m_timing, *KeyframeAnimationEffect::create(framesMixed).get()));
+ framesMixed.append(createDefaultKeyframe(CSSPropertyTransform, AnimationEffect::CompositeReplace, 1.0).get());
+ EXPECT_FALSE(isCandidateForAnimationOnCompositor(m_timing, *AnimatableValueKeyframeEffectModel::create(framesMixed).get()));
}
-TEST_F(AnimationCompositorAnimationsTest, isCandidateForAnimationOnCompositorKeyframeEffectMultipleFramesNotOkay)
+TEST_F(AnimationCompositorAnimationsTest, isCandidateForAnimationOnCompositorKeyframeEffectModel)
{
- KeyframeAnimationEffect::KeyframeVector framesSame;
+ AnimatableValueKeyframeVector framesSame;
framesSame.append(createDefaultKeyframe(CSSPropertyColor, AnimationEffect::CompositeReplace, 0.0).get());
framesSame.append(createDefaultKeyframe(CSSPropertyColor, AnimationEffect::CompositeReplace, 1.0).get());
- EXPECT_FALSE(isCandidateForAnimationOnCompositor(m_timing, *KeyframeAnimationEffect::create(framesSame).get()));
+ EXPECT_FALSE(isCandidateForAnimationOnCompositor(m_timing, *AnimatableValueKeyframeEffectModel::create(framesSame).get()));
- KeyframeAnimationEffect::KeyframeVector framesMixedProperties;
+ AnimatableValueKeyframeVector framesMixedProperties;
framesMixedProperties.append(createDefaultKeyframe(CSSPropertyOpacity, AnimationEffect::CompositeReplace, 0.0).get());
framesMixedProperties.append(createDefaultKeyframe(CSSPropertyColor, AnimationEffect::CompositeReplace, 1.0).get());
- EXPECT_FALSE(isCandidateForAnimationOnCompositor(m_timing, *KeyframeAnimationEffect::create(framesMixedProperties).get()));
-
- KeyframeAnimationEffect::KeyframeVector framesMixedOps;
- framesMixedOps.append(createDefaultKeyframe(CSSPropertyOpacity, AnimationEffect::CompositeReplace, 0.0).get());
- framesMixedOps.append(createDefaultKeyframe(CSSPropertyOpacity, AnimationEffect::CompositeAdd, 1.0).get());
- EXPECT_FALSE(isCandidateForAnimationOnCompositor(m_timing, *KeyframeAnimationEffect::create(framesMixedOps).get()));
+ EXPECT_FALSE(isCandidateForAnimationOnCompositor(m_timing, *AnimatableValueKeyframeEffectModel::create(framesMixedProperties).get()));
}
TEST_F(AnimationCompositorAnimationsTest, ConvertTimingForCompositorStartDelay)
@@ -477,13 +425,12 @@ TEST_F(AnimationCompositorAnimationsTest, isCandidateForAnimationOnCompositorTim
TEST_F(AnimationCompositorAnimationsTest, isCandidateForAnimationOnCompositorTimingFunctionCubic)
{
- // Cubic bezier are okay if we only have two keyframes
m_timing.timingFunction = m_cubicEaseTimingFunction;
- EXPECT_TRUE(isCandidateForAnimationOnCompositor(m_timing, *m_keyframeAnimationEffect2.get()));
+ EXPECT_FALSE(isCandidateForAnimationOnCompositor(m_timing, *m_keyframeAnimationEffect2.get()));
EXPECT_FALSE(isCandidateForAnimationOnCompositor(m_timing, *m_keyframeAnimationEffect5.get()));
m_timing.timingFunction = m_cubicCustomTimingFunction;
- EXPECT_TRUE(isCandidateForAnimationOnCompositor(m_timing, *m_keyframeAnimationEffect2.get()));
+ EXPECT_FALSE(isCandidateForAnimationOnCompositor(m_timing, *m_keyframeAnimationEffect2.get()));
EXPECT_FALSE(isCandidateForAnimationOnCompositor(m_timing, *m_keyframeAnimationEffect5.get()));
}
@@ -494,191 +441,65 @@ TEST_F(AnimationCompositorAnimationsTest, isCandidateForAnimationOnCompositorTim
EXPECT_FALSE(isCandidateForAnimationOnCompositor(m_timing, *m_keyframeAnimationEffect5.get()));
}
-TEST_F(AnimationCompositorAnimationsTest, isCandidateForAnimationOnCompositorTimingFunctionChainedEmpty)
-{
- RefPtr<ChainedTimingFunction> chainedEmpty = ChainedTimingFunction::create();
- m_timing.timingFunction = chainedEmpty;
- EXPECT_FALSE(isCandidateForAnimationOnCompositor(m_timing, *m_keyframeAnimationEffect2.get()));
- EXPECT_FALSE(isCandidateForAnimationOnCompositor(m_timing, *m_keyframeAnimationEffect5.get()));
-}
-
TEST_F(AnimationCompositorAnimationsTest, isCandidateForAnimationOnCompositorTimingFunctionChainedLinear)
{
- RefPtr<ChainedTimingFunction> chainedLinearSingle = ChainedTimingFunction::create();
- chainedLinearSingle->appendSegment(1.0, m_linearTimingFunction.get());
- m_timing.timingFunction = chainedLinearSingle;
EXPECT_TRUE(isCandidateForAnimationOnCompositor(m_timing, *m_keyframeAnimationEffect2.get()));
-
- RefPtr<ChainedTimingFunction> chainedLinearMultiple = ChainedTimingFunction::create();
- chainedLinearMultiple->appendSegment(0.25, m_linearTimingFunction.get());
- chainedLinearMultiple->appendSegment(0.5, m_linearTimingFunction.get());
- chainedLinearMultiple->appendSegment(0.75, m_linearTimingFunction.get());
- chainedLinearMultiple->appendSegment(1.0, m_linearTimingFunction.get());
- m_timing.timingFunction = chainedLinearMultiple;
EXPECT_TRUE(isCandidateForAnimationOnCompositor(m_timing, *m_keyframeAnimationEffect5.get()));
-
- // FIXME: Technically a chained timing function of linear functions don't
- // have to be aligned to keyframes. We don't support that currently as
- // nothing generates that yet.
}
TEST_F(AnimationCompositorAnimationsTest, isCandidateForAnimationOnCompositorTimingFunctionChainedCubicMatchingOffsets)
{
- RefPtr<ChainedTimingFunction> chainedSingleAGood = ChainedTimingFunction::create();
- chainedSingleAGood->appendSegment(1.0, m_cubicEaseTimingFunction.get());
- m_timing.timingFunction = chainedSingleAGood;
+ (*m_keyframeVector2)[0]->setEasing(m_cubicEaseTimingFunction.get());
+ m_keyframeAnimationEffect2 = AnimatableValueKeyframeEffectModel::create(*m_keyframeVector2);
EXPECT_TRUE(isCandidateForAnimationOnCompositor(m_timing, *m_keyframeAnimationEffect2.get()));
- RefPtr<ChainedTimingFunction> chainedSingleBGood = ChainedTimingFunction::create();
- chainedSingleBGood->appendSegment(1.0, m_cubicCustomTimingFunction.get());
- m_timing.timingFunction = chainedSingleBGood;
+ (*m_keyframeVector2)[0]->setEasing(m_cubicCustomTimingFunction.get());
+ m_keyframeAnimationEffect2 = AnimatableValueKeyframeEffectModel::create(*m_keyframeVector2);
EXPECT_TRUE(isCandidateForAnimationOnCompositor(m_timing, *m_keyframeAnimationEffect2.get()));
- RefPtr<ChainedTimingFunction> chainedMultipleGood = ChainedTimingFunction::create();
- chainedMultipleGood->appendSegment(0.25, m_cubicEaseTimingFunction.get());
- chainedMultipleGood->appendSegment(0.5, m_cubicCustomTimingFunction.get());
- chainedMultipleGood->appendSegment(0.75, m_cubicCustomTimingFunction.get());
- chainedMultipleGood->appendSegment(1.0, m_cubicCustomTimingFunction.get());
- m_timing.timingFunction = chainedMultipleGood;
+ (*m_keyframeVector5)[0]->setEasing(m_cubicEaseTimingFunction.get());
+ (*m_keyframeVector5)[1]->setEasing(m_cubicCustomTimingFunction.get());
+ (*m_keyframeVector5)[2]->setEasing(m_cubicCustomTimingFunction.get());
+ (*m_keyframeVector5)[3]->setEasing(m_cubicCustomTimingFunction.get());
+ m_keyframeAnimationEffect5 = AnimatableValueKeyframeEffectModel::create(*m_keyframeVector5);
EXPECT_TRUE(isCandidateForAnimationOnCompositor(m_timing, *m_keyframeAnimationEffect5.get()));
}
-TEST_F(AnimationCompositorAnimationsTest, isCandidateForAnimationOnCompositorTimingFunctionChainedCubicNonMatchingOffsets)
-{
- RefPtr<ChainedTimingFunction> chained0 = ChainedTimingFunction::create();
- chained0->appendSegment(0.5, m_cubicEaseTimingFunction.get());
- m_timing.timingFunction = chained0;
- EXPECT_FALSE(isCandidateForAnimationOnCompositor(m_timing, *m_keyframeAnimationEffect2.get()));
-
- RefPtr<ChainedTimingFunction> chained1 = ChainedTimingFunction::create();
- chained1->appendSegment(0.24, m_cubicEaseTimingFunction.get());
- chained1->appendSegment(0.5, m_cubicEaseTimingFunction.get());
- chained1->appendSegment(0.75, m_cubicEaseTimingFunction.get());
- chained1->appendSegment(1.0, m_cubicEaseTimingFunction.get());
- m_timing.timingFunction = chained1;
- EXPECT_FALSE(isCandidateForAnimationOnCompositor(m_timing, *m_keyframeAnimationEffect5.get()));
-
- RefPtr<ChainedTimingFunction> chained2 = ChainedTimingFunction::create();
- chained2->appendSegment(0.25, m_cubicEaseTimingFunction.get());
- chained2->appendSegment(0.51, m_cubicEaseTimingFunction.get());
- chained2->appendSegment(0.75, m_cubicEaseTimingFunction.get());
- chained2->appendSegment(1.0, m_cubicEaseTimingFunction.get());
- m_timing.timingFunction = chained2;
- EXPECT_FALSE(isCandidateForAnimationOnCompositor(m_timing, *m_keyframeAnimationEffect5.get()));
-
- RefPtr<ChainedTimingFunction> chained3 = ChainedTimingFunction::create();
- chained3->appendSegment(0.25, m_cubicEaseTimingFunction.get());
- chained3->appendSegment(0.5, m_cubicEaseTimingFunction.get());
- chained3->appendSegment(0.75, m_cubicEaseTimingFunction.get());
- chained3->appendSegment(0.8, m_cubicEaseTimingFunction.get());
- m_timing.timingFunction = chained3;
- EXPECT_FALSE(isCandidateForAnimationOnCompositor(m_timing, *m_keyframeAnimationEffect5.get()));
-
- RefPtr<ChainedTimingFunction> chained4 = ChainedTimingFunction::create();
- chained4->appendSegment(0.25, m_cubicEaseTimingFunction.get());
- chained4->appendSegment(0.5, m_cubicEaseTimingFunction.get());
- chained4->appendSegment(0.75, m_cubicEaseTimingFunction.get());
- chained4->appendSegment(1.1, m_cubicEaseTimingFunction.get());
- m_timing.timingFunction = chained4;
- EXPECT_FALSE(isCandidateForAnimationOnCompositor(m_timing, *m_keyframeAnimationEffect5.get()));
-}
-
-TEST_F(AnimationCompositorAnimationsTest, isCandidateForAnimationOnCompositorTimingFunctionMissingFrames)
-{
- // Missing first
- RefPtr<ChainedTimingFunction> chained1 = ChainedTimingFunction::create();
- chained1->appendSegment(0.5, m_cubicEaseTimingFunction.get());
- chained1->appendSegment(0.75, m_cubicEaseTimingFunction.get());
- chained1->appendSegment(1.0, m_cubicEaseTimingFunction.get());
- m_timing.timingFunction = chained1;
- EXPECT_FALSE(isCandidateForAnimationOnCompositor(m_timing, *m_keyframeAnimationEffect5.get()));
-
- // Missing middle
- RefPtr<ChainedTimingFunction> chained2 = ChainedTimingFunction::create();
- chained2->appendSegment(0.25, m_cubicEaseTimingFunction.get());
- chained2->appendSegment(0.75, m_cubicEaseTimingFunction.get());
- chained2->appendSegment(1.0, m_cubicEaseTimingFunction.get());
- m_timing.timingFunction = chained2;
- EXPECT_FALSE(isCandidateForAnimationOnCompositor(m_timing, *m_keyframeAnimationEffect5.get()));
-
- // Missing last
- RefPtr<ChainedTimingFunction> chained3 = ChainedTimingFunction::create();
- chained3->appendSegment(0.25, m_cubicEaseTimingFunction.get());
- chained3->appendSegment(0.5, m_cubicEaseTimingFunction.get());
- chained3->appendSegment(0.75, m_cubicEaseTimingFunction.get());
- m_timing.timingFunction = chained3;
- EXPECT_FALSE(isCandidateForAnimationOnCompositor(m_timing, *m_keyframeAnimationEffect5.get()));
-}
-
-TEST_F(AnimationCompositorAnimationsTest, isCandidateForAnimationOnCompositorTimingFunctionToManyFrames)
-{
- RefPtr<ChainedTimingFunction> chained1 = ChainedTimingFunction::create();
- chained1->appendSegment(0.1, m_cubicEaseTimingFunction.get());
- chained1->appendSegment(0.5, m_cubicEaseTimingFunction.get());
- m_timing.timingFunction = chained1;
- EXPECT_FALSE(isCandidateForAnimationOnCompositor(m_timing, *m_keyframeAnimationEffect2.get()));
-
- RefPtr<ChainedTimingFunction> chained2 = ChainedTimingFunction::create();
- chained2->appendSegment(0.1, m_cubicEaseTimingFunction.get());
- chained2->appendSegment(0.25, m_cubicEaseTimingFunction.get());
- chained2->appendSegment(0.5, m_cubicEaseTimingFunction.get());
- chained2->appendSegment(0.75, m_cubicEaseTimingFunction.get());
- chained2->appendSegment(1.0, m_cubicEaseTimingFunction.get());
- m_timing.timingFunction = chained2;
- EXPECT_FALSE(isCandidateForAnimationOnCompositor(m_timing, *m_keyframeAnimationEffect5.get()));
-}
-
TEST_F(AnimationCompositorAnimationsTest, isCandidateForAnimationOnCompositorTimingFunctionMixedGood)
{
- RefPtr<ChainedTimingFunction> chainedMixed = ChainedTimingFunction::create();
- chainedMixed->appendSegment(0.25, m_linearTimingFunction.get());
- chainedMixed->appendSegment(0.5, m_cubicEaseTimingFunction.get());
- chainedMixed->appendSegment(0.75, m_cubicEaseTimingFunction.get());
- chainedMixed->appendSegment(1.0, m_linearTimingFunction.get());
- m_timing.timingFunction = chainedMixed;
+ (*m_keyframeVector5)[0]->setEasing(m_linearTimingFunction.get());
+ (*m_keyframeVector5)[1]->setEasing(m_cubicEaseTimingFunction.get());
+ (*m_keyframeVector5)[2]->setEasing(m_cubicEaseTimingFunction.get());
+ (*m_keyframeVector5)[3]->setEasing(m_linearTimingFunction.get());
+ m_keyframeAnimationEffect5 = AnimatableValueKeyframeEffectModel::create(*m_keyframeVector5);
EXPECT_TRUE(isCandidateForAnimationOnCompositor(m_timing, *m_keyframeAnimationEffect5.get()));
}
TEST_F(AnimationCompositorAnimationsTest, isCandidateForAnimationOnCompositorTimingFunctionWithStepNotOkay)
{
- RefPtr<ChainedTimingFunction> chainedStepSingle = ChainedTimingFunction::create();
- chainedStepSingle->appendSegment(1.0, m_stepTimingFunction.get());
- m_timing.timingFunction = chainedStepSingle;
+ (*m_keyframeVector2)[0]->setEasing(m_stepTimingFunction.get());
+ m_keyframeAnimationEffect2 = AnimatableValueKeyframeEffectModel::create(*m_keyframeVector2);
EXPECT_FALSE(isCandidateForAnimationOnCompositor(m_timing, *m_keyframeAnimationEffect2.get()));
- RefPtr<ChainedTimingFunction> chainedStepMixedA = ChainedTimingFunction::create();
- chainedStepMixedA->appendSegment(0.25, m_stepTimingFunction.get());
- chainedStepMixedA->appendSegment(0.5, m_linearTimingFunction.get());
- chainedStepMixedA->appendSegment(1.0, m_cubicEaseTimingFunction.get());
- m_timing.timingFunction = chainedStepMixedA;
+ (*m_keyframeVector5)[0]->setEasing(m_stepTimingFunction.get());
+ (*m_keyframeVector5)[1]->setEasing(m_linearTimingFunction.get());
+ (*m_keyframeVector5)[2]->setEasing(m_cubicEaseTimingFunction.get());
+ (*m_keyframeVector5)[3]->setEasing(m_linearTimingFunction.get());
+ m_keyframeAnimationEffect5 = AnimatableValueKeyframeEffectModel::create(*m_keyframeVector5);
EXPECT_FALSE(isCandidateForAnimationOnCompositor(m_timing, *m_keyframeAnimationEffect5.get()));
- RefPtr<ChainedTimingFunction> chainedStepMixedB = ChainedTimingFunction::create();
- chainedStepMixedB->appendSegment(0.25, m_linearTimingFunction.get());
- chainedStepMixedB->appendSegment(0.5, m_stepTimingFunction.get());
- chainedStepMixedB->appendSegment(1.0, m_cubicEaseTimingFunction.get());
- m_timing.timingFunction = chainedStepMixedB;
+ (*m_keyframeVector5)[0]->setEasing(m_linearTimingFunction.get());
+ (*m_keyframeVector5)[1]->setEasing(m_stepTimingFunction.get());
+ (*m_keyframeVector5)[2]->setEasing(m_cubicEaseTimingFunction.get());
+ (*m_keyframeVector5)[3]->setEasing(m_linearTimingFunction.get());
+ m_keyframeAnimationEffect5 = AnimatableValueKeyframeEffectModel::create(*m_keyframeVector5);
EXPECT_FALSE(isCandidateForAnimationOnCompositor(m_timing, *m_keyframeAnimationEffect5.get()));
- RefPtr<ChainedTimingFunction> chainedStepMixedC = ChainedTimingFunction::create();
- chainedStepMixedC->appendSegment(0.25, m_linearTimingFunction.get());
- chainedStepMixedC->appendSegment(0.5, m_cubicEaseTimingFunction.get());
- chainedStepMixedC->appendSegment(1.0, m_stepTimingFunction.get());
- m_timing.timingFunction = chainedStepMixedC;
- EXPECT_FALSE(isCandidateForAnimationOnCompositor(m_timing, *m_keyframeAnimationEffect5.get()));
-}
-
-TEST_F(AnimationCompositorAnimationsTest, isCandidateForAnimationOnCompositorTimingFunctionNestedNotOkay)
-{
- RefPtr<ChainedTimingFunction> chainedChild = ChainedTimingFunction::create();
- chainedChild->appendSegment(1.0, m_linearTimingFunction.get());
-
- RefPtr<ChainedTimingFunction> chainedParent = ChainedTimingFunction::create();
- chainedParent->appendSegment(0.25, m_linearTimingFunction.get());
- chainedParent->appendSegment(0.5, chainedChild.get());
- chainedParent->appendSegment(0.75, m_linearTimingFunction.get());
- chainedParent->appendSegment(1.0, m_linearTimingFunction.get());
- m_timing.timingFunction = chainedParent;
+ (*m_keyframeVector5)[0]->setEasing(m_linearTimingFunction.get());
+ (*m_keyframeVector5)[1]->setEasing(m_cubicEaseTimingFunction.get());
+ (*m_keyframeVector5)[2]->setEasing(m_cubicEaseTimingFunction.get());
+ (*m_keyframeVector5)[3]->setEasing(m_stepTimingFunction.get());
+ m_keyframeAnimationEffect5 = AnimatableValueKeyframeEffectModel::create(*m_keyframeVector5);
EXPECT_FALSE(isCandidateForAnimationOnCompositor(m_timing, *m_keyframeAnimationEffect5.get()));
}
@@ -686,35 +507,27 @@ TEST_F(AnimationCompositorAnimationsTest, isCandidateForAnimationOnCompositor)
{
Timing linearTiming(createCompositableTiming());
- RefPtr<TimingFunction> cubicTimingFunc = CubicBezierTimingFunction::preset(CubicBezierTimingFunction::EaseIn);
- Timing cubicTiming(createCompositableTiming());
- cubicTiming.timingFunction = cubicTimingFunc;
-
- RefPtr<ChainedTimingFunction> chainedTimingFunc = ChainedTimingFunction::create();
- chainedTimingFunc->appendSegment(0.5, m_linearTimingFunction.get());
- chainedTimingFunc->appendSegment(1.0, cubicTimingFunc.get());
- Timing chainedTiming(createCompositableTiming());
- chainedTiming.timingFunction = chainedTimingFunc;
-
- KeyframeAnimationEffect::KeyframeVector basicFramesVector;
+ AnimatableValueKeyframeVector basicFramesVector;
basicFramesVector.append(createDefaultKeyframe(CSSPropertyOpacity, AnimationEffect::CompositeReplace, 0.0).get());
basicFramesVector.append(createDefaultKeyframe(CSSPropertyOpacity, AnimationEffect::CompositeReplace, 1.0).get());
- RefPtr<KeyframeAnimationEffect> basicFrames = KeyframeAnimationEffect::create(basicFramesVector).get();
-
- EXPECT_TRUE(isCandidateForAnimationOnCompositor(linearTiming, *basicFrames.get()));
- EXPECT_TRUE(isCandidateForAnimationOnCompositor(cubicTiming, *basicFrames.get()));
- // number of timing function and keyframes don't match
- EXPECT_FALSE(isCandidateForAnimationOnCompositor(chainedTiming, *basicFrames.get()));
- KeyframeAnimationEffect::KeyframeVector nonBasicFramesVector;
+ AnimatableValueKeyframeVector nonBasicFramesVector;
nonBasicFramesVector.append(createDefaultKeyframe(CSSPropertyOpacity, AnimationEffect::CompositeReplace, 0.0).get());
nonBasicFramesVector.append(createDefaultKeyframe(CSSPropertyOpacity, AnimationEffect::CompositeReplace, 0.5).get());
nonBasicFramesVector.append(createDefaultKeyframe(CSSPropertyOpacity, AnimationEffect::CompositeReplace, 1.0).get());
- RefPtr<KeyframeAnimationEffect> nonBasicFrames = KeyframeAnimationEffect::create(nonBasicFramesVector).get();
+ basicFramesVector[0]->setEasing(m_linearTimingFunction.get());
+ RefPtrWillBeRawPtr<AnimatableValueKeyframeEffectModel> basicFrames = AnimatableValueKeyframeEffectModel::create(basicFramesVector).get();
+ EXPECT_TRUE(isCandidateForAnimationOnCompositor(linearTiming, *basicFrames.get()));
+
+ basicFramesVector[0]->setEasing(CubicBezierTimingFunction::preset(CubicBezierTimingFunction::EaseIn));
+ basicFrames = AnimatableValueKeyframeEffectModel::create(basicFramesVector).get();
+ EXPECT_TRUE(isCandidateForAnimationOnCompositor(linearTiming, *basicFrames.get()));
+
+ nonBasicFramesVector[0]->setEasing(m_linearTimingFunction.get());
+ nonBasicFramesVector[1]->setEasing(CubicBezierTimingFunction::preset(CubicBezierTimingFunction::EaseIn));
+ RefPtrWillBeRawPtr<AnimatableValueKeyframeEffectModel> nonBasicFrames = AnimatableValueKeyframeEffectModel::create(nonBasicFramesVector).get();
EXPECT_TRUE(CompositorAnimations::instance()->isCandidateForAnimationOnCompositor(linearTiming, *nonBasicFrames.get()));
- EXPECT_FALSE(CompositorAnimations::instance()->isCandidateForAnimationOnCompositor(cubicTiming, *nonBasicFrames.get()));
- EXPECT_TRUE(CompositorAnimations::instance()->isCandidateForAnimationOnCompositor(chainedTiming, *nonBasicFrames.get()));
}
// -----------------------------------------------------------------------
@@ -723,7 +536,7 @@ TEST_F(AnimationCompositorAnimationsTest, isCandidateForAnimationOnCompositor)
TEST_F(AnimationCompositorAnimationsTest, createSimpleOpacityAnimation)
{
// Animation to convert
- RefPtr<KeyframeAnimationEffect> effect = createKeyframeAnimationEffect(
+ RefPtrWillBeRawPtr<AnimatableValueKeyframeEffectModel> effect = createKeyframeEffectModel(
createReplaceOpKeyframe(CSSPropertyOpacity, AnimatableDouble::create(2.0).get(), 0),
createReplaceOpKeyframe(CSSPropertyOpacity, AnimatableDouble::create(5.0).get(), 1.0));
// --
@@ -768,7 +581,7 @@ TEST_F(AnimationCompositorAnimationsTest, createSimpleOpacityAnimation)
TEST_F(AnimationCompositorAnimationsTest, createSimpleOpacityAnimationDuration)
{
// Animation to convert
- RefPtr<KeyframeAnimationEffect> effect = createKeyframeAnimationEffect(
+ RefPtrWillBeRawPtr<AnimatableValueKeyframeEffectModel> effect = createKeyframeEffectModel(
createReplaceOpKeyframe(CSSPropertyOpacity, AnimatableDouble::create(2.0).get(), 0),
createReplaceOpKeyframe(CSSPropertyOpacity, AnimatableDouble::create(5.0).get(), 1.0));
@@ -815,7 +628,7 @@ TEST_F(AnimationCompositorAnimationsTest, createSimpleOpacityAnimationDuration)
TEST_F(AnimationCompositorAnimationsTest, createMultipleKeyframeOpacityAnimationLinear)
{
// Animation to convert
- RefPtr<KeyframeAnimationEffect> effect = createKeyframeAnimationEffect(
+ RefPtrWillBeRawPtr<AnimatableValueKeyframeEffectModel> effect = createKeyframeEffectModel(
createReplaceOpKeyframe(CSSPropertyOpacity, AnimatableDouble::create(2.0).get(), 0),
createReplaceOpKeyframe(CSSPropertyOpacity, AnimatableDouble::create(-1.0).get(), 0.25),
createReplaceOpKeyframe(CSSPropertyOpacity, AnimatableDouble::create(20.0).get(), 0.5),
@@ -868,7 +681,7 @@ TEST_F(AnimationCompositorAnimationsTest, createMultipleKeyframeOpacityAnimation
TEST_F(AnimationCompositorAnimationsTest, createSimpleOpacityAnimationStartDelay)
{
// Animation to convert
- RefPtr<KeyframeAnimationEffect> effect = createKeyframeAnimationEffect(
+ RefPtrWillBeRawPtr<AnimatableValueKeyframeEffectModel> effect = createKeyframeEffectModel(
createReplaceOpKeyframe(CSSPropertyOpacity, AnimatableDouble::create(2.0).get(), 0),
createReplaceOpKeyframe(CSSPropertyOpacity, AnimatableDouble::create(5.0).get(), 1.0));
@@ -917,18 +730,17 @@ TEST_F(AnimationCompositorAnimationsTest, createSimpleOpacityAnimationStartDelay
TEST_F(AnimationCompositorAnimationsTest, createMultipleKeyframeOpacityAnimationChained)
{
// Animation to convert
- RefPtr<KeyframeAnimationEffect> effect = createKeyframeAnimationEffect(
- createReplaceOpKeyframe(CSSPropertyOpacity, AnimatableDouble::create(2.0).get(), 0),
- createReplaceOpKeyframe(CSSPropertyOpacity, AnimatableDouble::create(-1.0).get(), 0.25),
- createReplaceOpKeyframe(CSSPropertyOpacity, AnimatableDouble::create(20.0).get(), 0.5),
- createReplaceOpKeyframe(CSSPropertyOpacity, AnimatableDouble::create(5.0).get(), 1.0));
-
- RefPtr<ChainedTimingFunction> chainedTimingFunction = ChainedTimingFunction::create();
- chainedTimingFunction->appendSegment(0.25, m_cubicEaseTimingFunction.get());
- chainedTimingFunction->appendSegment(0.5, m_linearTimingFunction.get());
- chainedTimingFunction->appendSegment(1.0, m_cubicCustomTimingFunction.get());
-
- m_timing.timingFunction = chainedTimingFunction;
+ AnimatableValueKeyframeVector frames;
+ frames.append(createReplaceOpKeyframe(CSSPropertyOpacity, AnimatableDouble::create(2.0).get(), 0));
+ frames.append(createReplaceOpKeyframe(CSSPropertyOpacity, AnimatableDouble::create(-1.0).get(), 0.25));
+ frames.append(createReplaceOpKeyframe(CSSPropertyOpacity, AnimatableDouble::create(20.0).get(), 0.5));
+ frames.append(createReplaceOpKeyframe(CSSPropertyOpacity, AnimatableDouble::create(5.0).get(), 1.0));
+ frames[0]->setEasing(m_cubicEaseTimingFunction.get());
+ frames[1]->setEasing(m_linearTimingFunction.get());
+ frames[2]->setEasing(m_cubicCustomTimingFunction.get());
+ RefPtrWillBeRawPtr<AnimatableValueKeyframeEffectModel> effect = AnimatableValueKeyframeEffectModel::create(frames);
+
+ m_timing.timingFunction = m_linearTimingFunction.get();
m_timing.iterationDuration = 2.0;
m_timing.iterationCount = 10;
m_timing.direction = Timing::PlaybackDirectionAlternate;
@@ -976,20 +788,20 @@ TEST_F(AnimationCompositorAnimationsTest, createMultipleKeyframeOpacityAnimation
TEST_F(AnimationCompositorAnimationsTest, createReversedOpacityAnimation)
{
- // Animation to convert
- RefPtr<KeyframeAnimationEffect> effect = createKeyframeAnimationEffect(
- createReplaceOpKeyframe(CSSPropertyOpacity, AnimatableDouble::create(2.0).get(), 0),
- createReplaceOpKeyframe(CSSPropertyOpacity, AnimatableDouble::create(-1.0).get(), 0.25),
- createReplaceOpKeyframe(CSSPropertyOpacity, AnimatableDouble::create(20.0).get(), 0.5),
- createReplaceOpKeyframe(CSSPropertyOpacity, AnimatableDouble::create(5.0).get(), 1.0));
-
RefPtr<TimingFunction> cubicEasyFlipTimingFunction = CubicBezierTimingFunction::create(0.0, 0.0, 0.0, 1.0);
- RefPtr<ChainedTimingFunction> chainedTimingFunction = ChainedTimingFunction::create();
- chainedTimingFunction->appendSegment(0.25, CubicBezierTimingFunction::preset(CubicBezierTimingFunction::EaseIn));
- chainedTimingFunction->appendSegment(0.5, m_linearTimingFunction.get());
- chainedTimingFunction->appendSegment(1.0, cubicEasyFlipTimingFunction.get());
- m_timing.timingFunction = chainedTimingFunction;
+ // Animation to convert
+ AnimatableValueKeyframeVector frames;
+ frames.append(createReplaceOpKeyframe(CSSPropertyOpacity, AnimatableDouble::create(2.0).get(), 0));
+ frames.append(createReplaceOpKeyframe(CSSPropertyOpacity, AnimatableDouble::create(-1.0).get(), 0.25));
+ frames.append(createReplaceOpKeyframe(CSSPropertyOpacity, AnimatableDouble::create(20.0).get(), 0.5));
+ frames.append(createReplaceOpKeyframe(CSSPropertyOpacity, AnimatableDouble::create(5.0).get(), 1.0));
+ frames[0]->setEasing(CubicBezierTimingFunction::preset(CubicBezierTimingFunction::EaseIn));
+ frames[1]->setEasing(m_linearTimingFunction.get());
+ frames[2]->setEasing(cubicEasyFlipTimingFunction.get());
+ RefPtrWillBeRawPtr<AnimatableValueKeyframeEffectModel> effect = AnimatableValueKeyframeEffectModel::create(frames);
+
+ m_timing.timingFunction = m_linearTimingFunction.get();
m_timing.iterationCount = 10;
m_timing.direction = Timing::PlaybackDirectionAlternateReverse;
// --
@@ -1037,7 +849,7 @@ TEST_F(AnimationCompositorAnimationsTest, createReversedOpacityAnimation)
TEST_F(AnimationCompositorAnimationsTest, createReversedOpacityAnimationNegativeStartDelay)
{
// Animation to convert
- RefPtr<KeyframeAnimationEffect> effect = createKeyframeAnimationEffect(
+ RefPtrWillBeRawPtr<AnimatableValueKeyframeEffectModel> effect = createKeyframeEffectModel(
createReplaceOpKeyframe(CSSPropertyOpacity, AnimatableDouble::create(2.0).get(), 0),
createReplaceOpKeyframe(CSSPropertyOpacity, AnimatableDouble::create(5.0).get(), 1.0));
diff --git a/chromium/third_party/WebKit/Source/core/animation/CompositorAnimationsTestHelper.h b/chromium/third_party/WebKit/Source/core/animation/CompositorAnimationsTestHelper.h
index 732d34662e5..bb2761f75fc 100644
--- a/chromium/third_party/WebKit/Source/core/animation/CompositorAnimationsTestHelper.h
+++ b/chromium/third_party/WebKit/Source/core/animation/CompositorAnimationsTestHelper.h
@@ -131,7 +131,7 @@ private:
virtual void cryptographicallyRandomValues(unsigned char* buffer, size_t length) { ASSERT_NOT_REACHED(); }
private:
WebCompositorSupportMock** m_compositor;
- blink::WebCompositorSupport* compositorSupport() OVERRIDE { return *m_compositor; }
+ virtual blink::WebCompositorSupport* compositorSupport() OVERRIDE { return *m_compositor; }
};
WebCompositorSupportMock* m_mockCompositor;
diff --git a/chromium/third_party/WebKit/Source/core/animation/CompositorAnimationsTimingFunctionReverserTest.cpp b/chromium/third_party/WebKit/Source/core/animation/CompositorAnimationsTimingFunctionReverserTest.cpp
index 550b7f562c2..a62173efe62 100644
--- a/chromium/third_party/WebKit/Source/core/animation/CompositorAnimationsTimingFunctionReverserTest.cpp
+++ b/chromium/third_party/WebKit/Source/core/animation/CompositorAnimationsTimingFunctionReverserTest.cpp
@@ -32,8 +32,6 @@
#include "core/animation/CompositorAnimations.h"
-#include "core/platform/animation/TimingFunctionTestHelper.h"
-
#include "wtf/PassRefPtr.h"
#include "wtf/RefPtr.h"
@@ -60,7 +58,7 @@ public:
TEST_F(AnimationCompositorAnimationsTimingFunctionReverserTest, LinearReverse)
{
- RefPtr<TimingFunction> linearTiming = LinearTimingFunction::create();
+ RefPtr<TimingFunction> linearTiming = LinearTimingFunction::shared();
EXPECT_REFV_EQ(linearTiming, reverse(linearTiming));
}
@@ -84,24 +82,4 @@ TEST_F(AnimationCompositorAnimationsTimingFunctionReverserTest, CubicReverse)
EXPECT_REFV_EQ(cubicEaseTimingReversed, reverse(cubicEaseTiming));
}
-TEST_F(AnimationCompositorAnimationsTimingFunctionReverserTest, ChainedReverse)
-{
- RefPtr<TimingFunction> linearTiming = LinearTimingFunction::create();
- RefPtr<ChainedTimingFunction> chainedLinearSingle = ChainedTimingFunction::create();
- chainedLinearSingle->appendSegment(1.0, linearTiming.get());
- EXPECT_REFV_EQ(chainedLinearSingle, reverse(chainedLinearSingle));
-
- RefPtr<TimingFunction> cubicEaseInTiming = CubicBezierTimingFunction::preset(CubicBezierTimingFunction::EaseIn);
- RefPtr<TimingFunction> cubicEaseOutTiming = CubicBezierTimingFunction::preset(CubicBezierTimingFunction::EaseOut);
-
- RefPtr<ChainedTimingFunction> chainedMixed = ChainedTimingFunction::create();
- chainedMixed->appendSegment(0.75, chainedLinearSingle.get());
- chainedMixed->appendSegment(1.0, cubicEaseInTiming.get());
-
- RefPtr<ChainedTimingFunction> chainedMixedReversed = ChainedTimingFunction::create();
- chainedMixedReversed->appendSegment(0.25, cubicEaseOutTiming.get());
- chainedMixedReversed->appendSegment(1.0, chainedLinearSingle.get());
- EXPECT_REFV_EQ(chainedMixedReversed, reverse(chainedMixed));
-}
-
} // namespace
diff --git a/chromium/third_party/WebKit/Source/core/animation/css/CSSPendingAnimations.cpp b/chromium/third_party/WebKit/Source/core/animation/CompositorPendingAnimations.cpp
index 3a4ec03d29e..803e98c9953 100644
--- a/chromium/third_party/WebKit/Source/core/animation/css/CSSPendingAnimations.cpp
+++ b/chromium/third_party/WebKit/Source/core/animation/CompositorPendingAnimations.cpp
@@ -29,45 +29,53 @@
*/
#include "config.h"
-#include "core/animation/css/CSSPendingAnimations.h"
+#include "core/animation/CompositorPendingAnimations.h"
#include "core/animation/Animation.h"
-#include "core/animation/DocumentTimeline.h"
+#include "core/animation/AnimationTimeline.h"
#include "core/frame/FrameView.h"
+#include "core/page/Page.h"
+#include "core/rendering/RenderLayer.h"
namespace WebCore {
-void CSSPendingAnimations::add(Player* player)
+void CompositorPendingAnimations::add(AnimationPlayer* player)
{
- ASSERT(player->source()->isAnimation());
- // The actual start time is either this value, or the time that
- // this animation, or an animation that it is synchronized with
- // is started on the compositor.
- const double defaultStartTime = player->timeline().currentTime();
- m_pending.append(std::make_pair(player, defaultStartTime));
+ Page* page = player->timeline()->document()->page();
+ bool visible = page && page->visibilityState() == PageVisibilityStateVisible;
+ if (!player->hasStartTime() && !visible)
+ player->setStartTimeInternal(player->timeline()->currentTimeInternal(), true);
+
+ m_pending.append(player);
}
-bool CSSPendingAnimations::startPendingAnimations()
+bool CompositorPendingAnimations::startPendingAnimations()
{
- bool startedOnCompositor = false;
+ bool startedSynchronizedOnCompositor = false;
for (size_t i = 0; i < m_pending.size(); ++i) {
- if (m_pending[i].first->maybeStartAnimationOnCompositor())
- startedOnCompositor = true;
+ if (!m_pending[i]->hasActiveAnimationsOnCompositor() && m_pending[i]->maybeStartAnimationOnCompositor() && !m_pending[i]->hasStartTime())
+ startedSynchronizedOnCompositor = true;
}
- // If any animations were started on the compositor, all remaining
- // need to wait for a synchronized start time. Otherwise they may
- // start immediately.
- if (startedOnCompositor) {
- for (size_t i = 0; i < m_pending.size(); ++i)
- m_waitingForCompositorAnimationStart.append(m_pending[i].first);
+ // If any synchronized animations were started on the compositor, all
+ // remaning synchronized animations need to wait for the synchronized
+ // start time. Otherwise they may start immediately.
+ if (startedSynchronizedOnCompositor) {
+ for (size_t i = 0; i < m_pending.size(); ++i) {
+ if (!m_pending[i]->hasStartTime()) {
+ m_waitingForCompositorAnimationStart.append(m_pending[i]);
+ }
+ }
} else {
- for (size_t i = 0; i < m_pending.size(); ++i)
- m_pending[i].first->setStartTime(m_pending[i].second);
+ for (size_t i = 0; i < m_pending.size(); ++i) {
+ if (!m_pending[i]->hasStartTime()) {
+ m_pending[i]->setStartTimeInternal(m_pending[i]->timeline()->currentTimeInternal(), true);
+ }
+ }
}
m_pending.clear();
- if (startedOnCompositor || m_waitingForCompositorAnimationStart.isEmpty())
+ if (startedSynchronizedOnCompositor || m_waitingForCompositorAnimationStart.isEmpty())
return !m_waitingForCompositorAnimationStart.isEmpty();
// Check if we're still waiting for any compositor animations to start.
@@ -81,14 +89,20 @@ bool CSSPendingAnimations::startPendingAnimations()
return false;
}
-void CSSPendingAnimations::notifyCompositorAnimationStarted(double monotonicAnimationStartTime)
+void CompositorPendingAnimations::notifyCompositorAnimationStarted(double monotonicAnimationStartTime)
{
for (size_t i = 0; i < m_waitingForCompositorAnimationStart.size(); ++i) {
- Player* player = m_waitingForCompositorAnimationStart[i].get();
- player->setStartTime(monotonicAnimationStartTime - player->timeline().zeroTime());
+ AnimationPlayer* player = m_waitingForCompositorAnimationStart[i].get();
+ player->setStartTimeInternal(monotonicAnimationStartTime - player->timeline()->zeroTime(), true);
}
m_waitingForCompositorAnimationStart.clear();
}
+void CompositorPendingAnimations::trace(Visitor* visitor)
+{
+ visitor->trace(m_pending);
+ visitor->trace(m_waitingForCompositorAnimationStart);
+}
+
} // namespace
diff --git a/chromium/third_party/WebKit/Source/core/animation/css/CSSPendingAnimations.h b/chromium/third_party/WebKit/Source/core/animation/CompositorPendingAnimations.h
index 1bb3c28d4c0..179c255a917 100644
--- a/chromium/third_party/WebKit/Source/core/animation/css/CSSPendingAnimations.h
+++ b/chromium/third_party/WebKit/Source/core/animation/CompositorPendingAnimations.h
@@ -28,27 +28,35 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef CSSPendingAnimations_h
-#define CSSPendingAnimations_h
+#ifndef CompositorPendingAnimations_h
+#define CompositorPendingAnimations_h
-#include "core/animation/Player.h"
+#include "platform/heap/Handle.h"
#include "wtf/Vector.h"
namespace WebCore {
-// Used to synchronize the start of main-thread animations with compositor
-// animations when both classes of CSS Animations are triggered by the same recalc
-class CSSPendingAnimations FINAL {
+class AnimationPlayer;
+
+// Manages the starting of pending animations on the compositor following a
+// compositing update.
+// For CSS Animations, used to synchronize the start of main-thread animations
+// with compositor animations when both classes of CSS Animations are triggered
+// by the same recalc
+class CompositorPendingAnimations FINAL {
+ DISALLOW_ALLOCATION();
public:
- void add(Player*);
+ void add(AnimationPlayer*);
// Returns whether we are waiting for an animation to start and should
// service again on the next frame.
bool startPendingAnimations();
void notifyCompositorAnimationStarted(double monotonicAnimationStartTime);
+ void trace(Visitor*);
+
private:
- Vector<std::pair<RefPtr<Player>, double> > m_pending;
- Vector<RefPtr<Player> > m_waitingForCompositorAnimationStart;
+ WillBeHeapVector<RefPtrWillBeMember<AnimationPlayer> > m_pending;
+ WillBeHeapVector<RefPtrWillBeMember<AnimationPlayer> > m_waitingForCompositorAnimationStart;
};
} // namespace WebCore
diff --git a/chromium/third_party/WebKit/Source/core/animation/DocumentAnimation.h b/chromium/third_party/WebKit/Source/core/animation/DocumentAnimation.h
new file mode 100644
index 00000000000..f1f57265ec0
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/DocumentAnimation.h
@@ -0,0 +1,19 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef DocumentAnimation_h
+#define DocumentAnimation_h
+
+#include "core/dom/Document.h"
+
+namespace WebCore {
+
+class DocumentAnimation {
+public:
+ static AnimationTimeline* timeline(Document& document) { return &document.timeline(); }
+};
+
+} // namespace WebCore
+
+#endif // DocumentAnimation_h
diff --git a/chromium/third_party/WebKit/Source/core/animation/DocumentAnimation.idl b/chromium/third_party/WebKit/Source/core/animation/DocumentAnimation.idl
new file mode 100644
index 00000000000..d2c2861c8b1
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/DocumentAnimation.idl
@@ -0,0 +1,9 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+[
+ RuntimeEnabled=WebAnimationsAPI,
+] partial interface Document {
+ readonly attribute AnimationTimeline timeline;
+};
diff --git a/chromium/third_party/WebKit/Source/core/animation/DocumentAnimations.cpp b/chromium/third_party/WebKit/Source/core/animation/DocumentAnimations.cpp
index 34ea5ca4546..df35c02d312 100644
--- a/chromium/third_party/WebKit/Source/core/animation/DocumentAnimations.cpp
+++ b/chromium/third_party/WebKit/Source/core/animation/DocumentAnimations.cpp
@@ -31,78 +31,66 @@
#include "config.h"
#include "core/animation/DocumentAnimations.h"
-#include "core/animation/ActiveAnimations.h"
#include "core/animation/AnimationClock.h"
-#include "core/animation/DocumentTimeline.h"
+#include "core/animation/AnimationTimeline.h"
#include "core/dom/Document.h"
#include "core/dom/Element.h"
#include "core/dom/Node.h"
-#include "core/frame/Frame.h"
+#include "core/dom/NodeRenderStyle.h"
#include "core/frame/FrameView.h"
-#include "core/rendering/RenderLayerCompositor.h"
+#include "core/frame/LocalFrame.h"
#include "core/rendering/RenderView.h"
+#include "core/rendering/compositing/RenderLayerCompositor.h"
namespace WebCore {
namespace {
-void updateAnimationTiming(Document& document, double monotonicAnimationStartTime)
+void updateAnimationTiming(Document& document, TimingUpdateReason reason)
{
- document.animationClock().updateTime(monotonicAnimationStartTime);
- bool didTriggerStyleRecalc = document.timeline()->serviceAnimations();
- didTriggerStyleRecalc |= document.transitionTimeline()->serviceAnimations();
- if (!didTriggerStyleRecalc)
- document.animationClock().unfreeze();
+ document.timeline().serviceAnimations(reason);
}
-void dispatchAnimationEvents(Document& document)
-{
- document.timeline()->dispatchEvents();
- document.transitionTimeline()->dispatchEvents();
-}
+} // namespace
-void dispatchAnimationEventsAsync(Document& document)
+void DocumentAnimations::updateAnimationTimingForAnimationFrame(Document& document, double monotonicAnimationStartTime)
{
- document.timeline()->dispatchEventsAsync();
- document.transitionTimeline()->dispatchEventsAsync();
+ document.animationClock().updateTime(monotonicAnimationStartTime);
+ updateAnimationTiming(document, TimingUpdateForAnimationFrame);
}
-} // namespace
-
-void DocumentAnimations::serviceOnAnimationFrame(Document& document, double monotonicAnimationStartTime)
+void DocumentAnimations::updateOutdatedAnimationPlayersIfNeeded(Document& document)
{
- if (!RuntimeEnabledFeatures::webAnimationsCSSEnabled())
- return;
-
- updateAnimationTiming(document, monotonicAnimationStartTime);
- dispatchAnimationEvents(document);
+ if (needsOutdatedAnimationPlayerUpdate(document))
+ updateAnimationTiming(document, TimingUpdateOnDemand);
}
-void DocumentAnimations::serviceBeforeGetComputedStyle(Node& node, CSSPropertyID property)
+void DocumentAnimations::updateAnimationTimingForGetComputedStyle(Node& node, CSSPropertyID property)
{
- if (!RuntimeEnabledFeatures::webAnimationsCSSEnabled())
+ if (!node.isElementNode())
return;
-
- if (node.isElementNode()) {
- const Element& element = toElement(node);
- if (const ActiveAnimations* activeAnimations = element.activeAnimations()) {
- if (activeAnimations->hasActiveAnimationsOnCompositor(property))
- updateAnimationTiming(element.document(), monotonicallyIncreasingTime());
+ const Element& element = toElement(node);
+ if (RenderStyle* style = element.renderStyle()) {
+ if ((property == CSSPropertyOpacity && style->isRunningOpacityAnimationOnCompositor())
+ || ((property == CSSPropertyTransform || property == CSSPropertyWebkitTransform) && style->isRunningTransformAnimationOnCompositor())
+ || (property == CSSPropertyWebkitFilter && style->isRunningFilterAnimationOnCompositor())) {
+ updateAnimationTiming(element.document(), TimingUpdateOnDemand);
}
}
-
}
-void DocumentAnimations::serviceAfterStyleRecalc(Document& document)
+bool DocumentAnimations::needsOutdatedAnimationPlayerUpdate(const Document& document)
{
- if (!RuntimeEnabledFeatures::webAnimationsCSSEnabled())
- return;
+ return document.timeline().hasOutdatedAnimationPlayer();
+}
- if (document.cssPendingAnimations().startPendingAnimations() && document.view())
+void DocumentAnimations::startPendingAnimations(Document& document)
+{
+ ASSERT(document.lifecycle().state() == DocumentLifecycle::CompositingClean);
+ if (document.compositorPendingAnimations().startPendingAnimations()) {
+ ASSERT(document.view());
document.view()->scheduleAnimation();
-
- document.animationClock().unfreeze();
- dispatchAnimationEventsAsync(document);
+ }
}
} // namespace WebCore
diff --git a/chromium/third_party/WebKit/Source/core/animation/DocumentAnimations.h b/chromium/third_party/WebKit/Source/core/animation/DocumentAnimations.h
index b952c532ec1..f92f9942b49 100644
--- a/chromium/third_party/WebKit/Source/core/animation/DocumentAnimations.h
+++ b/chromium/third_party/WebKit/Source/core/animation/DocumentAnimations.h
@@ -31,7 +31,7 @@
#ifndef DocumentAnimations_h
#define DocumentAnimations_h
-#include "CSSPropertyNames.h"
+#include "core/CSSPropertyNames.h"
namespace WebCore {
@@ -39,11 +39,13 @@ class Document;
class FrameView;
class Node;
-class DocumentAnimations {
+class DocumentAnimations {
public:
- static void serviceOnAnimationFrame(Document&, double monotonicAnimationStartTime);
- static void serviceBeforeGetComputedStyle(Node&, CSSPropertyID);
- static void serviceAfterStyleRecalc(Document&);
+ static void updateAnimationTimingForAnimationFrame(Document&, double monotonicAnimationStartTime);
+ static bool needsOutdatedAnimationPlayerUpdate(const Document&);
+ static void updateOutdatedAnimationPlayersIfNeeded(Document&);
+ static void updateAnimationTimingForGetComputedStyle(Node&, CSSPropertyID);
+ static void startPendingAnimations(Document&);
private:
DocumentAnimations() { }
diff --git a/chromium/third_party/WebKit/Source/core/animation/DocumentTimeline.cpp b/chromium/third_party/WebKit/Source/core/animation/DocumentTimeline.cpp
deleted file mode 100644
index 21027f8b073..00000000000
--- a/chromium/third_party/WebKit/Source/core/animation/DocumentTimeline.cpp
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "core/animation/DocumentTimeline.h"
-
-#include "core/animation/ActiveAnimations.h"
-#include "core/animation/AnimationClock.h"
-#include "core/dom/Document.h"
-#include "core/frame/FrameView.h"
-
-namespace WebCore {
-
-// This value represents 1 frame at 30Hz plus a little bit of wiggle room.
-// TODO: Plumb a nominal framerate through and derive this value from that.
-const double DocumentTimeline::s_minimumDelay = 0.04;
-
-
-PassRefPtr<DocumentTimeline> DocumentTimeline::create(Document* document, PassOwnPtr<PlatformTiming> timing)
-{
- return adoptRef(new DocumentTimeline(document, timing));
-}
-
-DocumentTimeline::DocumentTimeline(Document* document, PassOwnPtr<PlatformTiming> timing)
- : m_zeroTime(nullValue())
- , m_document(document)
- , m_eventDistpachTimer(this, &DocumentTimeline::eventDispatchTimerFired)
-{
- if (!timing)
- m_timing = adoptPtr(new DocumentTimelineTiming(this));
- else
- m_timing = timing;
-
- ASSERT(document);
-}
-
-Player* DocumentTimeline::createPlayer(TimedItem* child)
-{
- RefPtr<Player> player = Player::create(*this, child);
- Player* result = player.get();
- m_players.append(player.release());
- if (m_document->view())
- m_timing->serviceOnNextFrame();
- return result;
-}
-
-Player* DocumentTimeline::play(TimedItem* child)
-{
- Player* player = createPlayer(child);
- player->setStartTime(currentTime());
- return player;
-}
-
-void DocumentTimeline::wake()
-{
- m_timing->serviceOnNextFrame();
-}
-
-bool DocumentTimeline::serviceAnimations()
-{
- TRACE_EVENT0("webkit", "DocumentTimeline::serviceAnimations");
-
- m_timing->cancelWake();
-
- double timeToNextEffect = std::numeric_limits<double>::infinity();
- bool didTriggerStyleRecalc = false;
- for (int i = m_players.size() - 1; i >= 0; --i) {
- double playerNextEffect;
- bool playerDidTriggerStyleRecalc;
- if (!m_players[i]->update(&playerNextEffect, &playerDidTriggerStyleRecalc))
- m_players.remove(i);
- didTriggerStyleRecalc |= playerDidTriggerStyleRecalc;
- if (playerNextEffect < timeToNextEffect)
- timeToNextEffect = playerNextEffect;
- }
-
- if (!m_players.isEmpty()) {
- if (timeToNextEffect < s_minimumDelay)
- m_timing->serviceOnNextFrame();
- else if (timeToNextEffect != std::numeric_limits<double>::infinity())
- m_timing->wakeAfter(timeToNextEffect - s_minimumDelay);
- }
-
- return didTriggerStyleRecalc;
-}
-
-void DocumentTimeline::setZeroTime(double zeroTime)
-{
- ASSERT(isNull(m_zeroTime));
- m_zeroTime = zeroTime;
- ASSERT(!isNull(m_zeroTime));
-}
-
-void DocumentTimeline::DocumentTimelineTiming::wakeAfter(double duration)
-{
- m_timer.startOneShot(duration);
-}
-
-void DocumentTimeline::DocumentTimelineTiming::cancelWake()
-{
- m_timer.stop();
-}
-
-void DocumentTimeline::DocumentTimelineTiming::serviceOnNextFrame()
-{
- if (m_timeline->m_document->view())
- m_timeline->m_document->view()->scheduleAnimation();
-}
-
-double DocumentTimeline::currentTime()
-{
- return m_document->animationClock().currentTime() - m_zeroTime;
-}
-
-void DocumentTimeline::pauseAnimationsForTesting(double pauseTime)
-{
- for (size_t i = 0; i < m_players.size(); i++) {
- m_players[i]->pauseForTesting();
- m_players[i]->setCurrentTime(pauseTime);
- }
-}
-
-void DocumentTimeline::dispatchEvents()
-{
- Vector<EventToDispatch> events = m_events;
- m_events.clear();
- for (size_t i = 0; i < events.size(); i++)
- events[i].target->dispatchEvent(events[i].event.release());
-}
-
-void DocumentTimeline::dispatchEventsAsync()
-{
- if (m_events.isEmpty() || m_eventDistpachTimer.isActive())
- return;
- m_eventDistpachTimer.startOneShot(0);
-}
-
-void DocumentTimeline::eventDispatchTimerFired(Timer<DocumentTimeline>*)
-{
- dispatchEvents();
-}
-
-size_t DocumentTimeline::numberOfActiveAnimationsForTesting() const
-{
- if (isNull(m_zeroTime))
- return 0;
- // Includes all players whose directly associated timed items
- // are current or in effect.
- if (isNull(m_zeroTime))
- return 0;
- size_t count = 0;
- for (size_t i = 0; i < m_players.size(); ++i) {
- const TimedItem* timedItem = m_players[i]->source();
- if (m_players[i]->hasStartTime())
- count += (timedItem && (timedItem->isCurrent() || timedItem->isInEffect()));
- }
- return count;
-}
-
-} // namespace
diff --git a/chromium/third_party/WebKit/Source/core/animation/EffectInput.cpp b/chromium/third_party/WebKit/Source/core/animation/EffectInput.cpp
new file mode 100644
index 00000000000..466052c1346
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/EffectInput.cpp
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "core/animation/EffectInput.h"
+
+#include "bindings/v8/Dictionary.h"
+#include "core/animation/AnimationHelpers.h"
+#include "core/animation/KeyframeEffectModel.h"
+#include "core/animation/StringKeyframe.h"
+#include "core/css/parser/BisonCSSParser.h"
+#include "core/css/resolver/CSSToStyleMap.h"
+#include "core/css/resolver/StyleResolver.h"
+#include "core/dom/Element.h"
+#include "wtf/NonCopyingSort.h"
+
+namespace WebCore {
+
+PassRefPtrWillBeRawPtr<AnimationEffect> EffectInput::convert(Element* element, const Vector<Dictionary>& keyframeDictionaryVector, ExceptionState& exceptionState)
+{
+ // FIXME: Remove the dependency on element.
+ if (!element)
+ return nullptr;
+
+ StyleSheetContents* styleSheetContents = element->document().elementSheet().contents();
+ StringKeyframeVector keyframes;
+ bool everyFrameHasOffset = true;
+ bool looselySortedByOffset = true;
+ double lastOffset = -std::numeric_limits<double>::infinity();
+
+ for (size_t i = 0; i < keyframeDictionaryVector.size(); ++i) {
+ RefPtrWillBeRawPtr<StringKeyframe> keyframe = StringKeyframe::create();
+
+ bool frameHasOffset = false;
+ double offset;
+ if (keyframeDictionaryVector[i].get("offset", offset)) {
+ // Keyframes with offsets outside the range [0.0, 1.0] are ignored.
+ if (std::isnan(offset) || offset < 0 || offset > 1)
+ continue;
+
+ frameHasOffset = true;
+ // The JS value null gets converted to 0 so we need to check whether the original value is null.
+ if (offset == 0) {
+ ScriptValue scriptValue;
+ if (keyframeDictionaryVector[i].get("offset", scriptValue) && scriptValue.isNull())
+ frameHasOffset = false;
+ }
+ if (frameHasOffset) {
+ keyframe->setOffset(offset);
+ if (offset < lastOffset)
+ looselySortedByOffset = false;
+ lastOffset = offset;
+ }
+ }
+ everyFrameHasOffset = everyFrameHasOffset && frameHasOffset;
+
+ keyframes.append(keyframe);
+
+ String compositeString;
+ keyframeDictionaryVector[i].get("composite", compositeString);
+ if (compositeString == "add")
+ keyframe->setComposite(AnimationEffect::CompositeAdd);
+
+ String timingFunctionString;
+ if (keyframeDictionaryVector[i].get("easing", timingFunctionString)) {
+ if (RefPtrWillBeRawPtr<CSSValue> timingFunctionValue = BisonCSSParser::parseAnimationTimingFunctionValue(timingFunctionString))
+ keyframe->setEasing(CSSToStyleMap::mapAnimationTimingFunction(timingFunctionValue.get(), true));
+ }
+
+ Vector<String> keyframeProperties;
+ keyframeDictionaryVector[i].getOwnPropertyNames(keyframeProperties);
+ for (size_t j = 0; j < keyframeProperties.size(); ++j) {
+ String property = keyframeProperties[j];
+ CSSPropertyID id = camelCaseCSSPropertyNameToID(property);
+ if (id == CSSPropertyInvalid)
+ continue;
+ String value;
+ keyframeDictionaryVector[i].get(property, value);
+ keyframe->setPropertyValue(id, value, styleSheetContents);
+ }
+ }
+
+ if (!looselySortedByOffset) {
+ if (!everyFrameHasOffset) {
+ exceptionState.throwDOMException(InvalidModificationError, "Keyframes are not loosely sorted by offset.");
+ return nullptr;
+ }
+ nonCopyingSort(keyframes.begin(), keyframes.end(), Keyframe::compareOffsets);
+ }
+
+ RefPtrWillBeRawPtr<StringKeyframeEffectModel> keyframeEffectModel = StringKeyframeEffectModel::create(keyframes);
+ if (!keyframeEffectModel->isReplaceOnly()) {
+ exceptionState.throwDOMException(NotSupportedError, "Partial keyframes are not supported.");
+ return nullptr;
+ }
+ keyframeEffectModel->forceConversionsToAnimatableValues(element);
+
+ return keyframeEffectModel;
+}
+
+} // namespace WebCore
diff --git a/chromium/third_party/WebKit/Source/core/animation/EffectInput.h b/chromium/third_party/WebKit/Source/core/animation/EffectInput.h
new file mode 100644
index 00000000000..e8948637813
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/EffectInput.h
@@ -0,0 +1,25 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef EffectInput_h
+#define EffectInput_h
+
+#include "core/animation/AnimationEffect.h"
+#include "wtf/Vector.h"
+
+namespace WebCore {
+
+class AnimationEffect;
+class Dictionary;
+class Element;
+class ExceptionState;
+
+class EffectInput {
+public:
+ static PassRefPtrWillBeRawPtr<AnimationEffect> convert(Element*, const Vector<Dictionary>& keyframeDictionaryVector, ExceptionState&);
+};
+
+} // namespace WebCore
+
+#endif
diff --git a/chromium/third_party/WebKit/Source/core/animation/EffectInputTest.cpp b/chromium/third_party/WebKit/Source/core/animation/EffectInputTest.cpp
new file mode 100644
index 00000000000..d8e174ce2a0
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/EffectInputTest.cpp
@@ -0,0 +1,125 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "config.h"
+#include "core/animation/EffectInput.h"
+
+#include "bindings/v8/Dictionary.h"
+#include "core/animation/AnimationTestHelper.h"
+#include "core/animation/KeyframeEffectModel.h"
+#include "core/dom/Document.h"
+#include "core/dom/Element.h"
+#include <gtest/gtest.h>
+#include <v8.h>
+
+using namespace WebCore;
+
+namespace {
+
+class AnimationEffectInputTest : public ::testing::Test {
+protected:
+ AnimationEffectInputTest()
+ : document(Document::create())
+ , element(document->createElement("foo", ASSERT_NO_EXCEPTION))
+ , m_isolate(v8::Isolate::GetCurrent())
+ , m_scope(m_isolate)
+ {
+ }
+
+ RefPtrWillBePersistent<Document> document;
+ RefPtrWillBePersistent<Element> element;
+ TrackExceptionState exceptionState;
+ v8::Isolate* m_isolate;
+
+private:
+ V8TestingScope m_scope;
+};
+
+TEST_F(AnimationEffectInputTest, SortedOffsets)
+{
+ Vector<Dictionary> jsKeyframes;
+ v8::Handle<v8::Object> keyframe1 = v8::Object::New(m_isolate);
+ v8::Handle<v8::Object> keyframe2 = v8::Object::New(m_isolate);
+
+ setV8ObjectPropertyAsString(keyframe1, "width", "100px");
+ setV8ObjectPropertyAsString(keyframe1, "offset", "0");
+ setV8ObjectPropertyAsString(keyframe2, "width", "0px");
+ setV8ObjectPropertyAsString(keyframe2, "offset", "1");
+
+ jsKeyframes.append(Dictionary(keyframe1, m_isolate));
+ jsKeyframes.append(Dictionary(keyframe2, m_isolate));
+
+ RefPtrWillBeRawPtr<AnimationEffect> animationEffect = EffectInput::convert(element.get(), jsKeyframes, exceptionState);
+ EXPECT_FALSE(exceptionState.hadException());
+ const KeyframeEffectModelBase& keyframeEffect = *toKeyframeEffectModelBase(animationEffect.get());
+ EXPECT_EQ(1.0, keyframeEffect.getFrames()[1]->offset());
+}
+
+TEST_F(AnimationEffectInputTest, UnsortedOffsets)
+{
+ Vector<Dictionary> jsKeyframes;
+ v8::Handle<v8::Object> keyframe1 = v8::Object::New(m_isolate);
+ v8::Handle<v8::Object> keyframe2 = v8::Object::New(m_isolate);
+
+ setV8ObjectPropertyAsString(keyframe1, "width", "0px");
+ setV8ObjectPropertyAsString(keyframe1, "offset", "1");
+ setV8ObjectPropertyAsString(keyframe2, "width", "100px");
+ setV8ObjectPropertyAsString(keyframe2, "offset", "0");
+
+ jsKeyframes.append(Dictionary(keyframe1, m_isolate));
+ jsKeyframes.append(Dictionary(keyframe2, m_isolate));
+
+ RefPtrWillBeRawPtr<AnimationEffect> animationEffect = EffectInput::convert(element.get(), jsKeyframes, exceptionState);
+ EXPECT_FALSE(exceptionState.hadException());
+ const KeyframeEffectModelBase& keyframeEffect = *toKeyframeEffectModelBase(animationEffect.get());
+ EXPECT_EQ(1.0, keyframeEffect.getFrames()[1]->offset());
+}
+
+TEST_F(AnimationEffectInputTest, LooslySorted)
+{
+ Vector<Dictionary> jsKeyframes;
+ v8::Handle<v8::Object> keyframe1 = v8::Object::New(m_isolate);
+ v8::Handle<v8::Object> keyframe2 = v8::Object::New(m_isolate);
+ v8::Handle<v8::Object> keyframe3 = v8::Object::New(m_isolate);
+
+ setV8ObjectPropertyAsString(keyframe1, "width", "100px");
+ setV8ObjectPropertyAsString(keyframe1, "offset", "0");
+ setV8ObjectPropertyAsString(keyframe2, "width", "200px");
+ setV8ObjectPropertyAsString(keyframe3, "width", "0px");
+ setV8ObjectPropertyAsString(keyframe3, "offset", "1");
+
+ jsKeyframes.append(Dictionary(keyframe1, m_isolate));
+ jsKeyframes.append(Dictionary(keyframe2, m_isolate));
+ jsKeyframes.append(Dictionary(keyframe3, m_isolate));
+
+ RefPtrWillBeRawPtr<AnimationEffect> animationEffect = EffectInput::convert(element.get(), jsKeyframes, exceptionState);
+ EXPECT_FALSE(exceptionState.hadException());
+ const KeyframeEffectModelBase& keyframeEffect = *toKeyframeEffectModelBase(animationEffect.get());
+ EXPECT_EQ(1, keyframeEffect.getFrames()[2]->offset());
+}
+
+TEST_F(AnimationEffectInputTest, Invalid)
+{
+ // Not loosely sorted by offset, and there exists a keyframe with null offset.
+ Vector<Dictionary> jsKeyframes;
+ v8::Handle<v8::Object> keyframe1 = v8::Object::New(m_isolate);
+ v8::Handle<v8::Object> keyframe2 = v8::Object::New(m_isolate);
+ v8::Handle<v8::Object> keyframe3 = v8::Object::New(m_isolate);
+
+ setV8ObjectPropertyAsString(keyframe1, "width", "0px");
+ setV8ObjectPropertyAsString(keyframe1, "offset", "1");
+ setV8ObjectPropertyAsString(keyframe2, "width", "200px");
+ setV8ObjectPropertyAsString(keyframe3, "width", "100px");
+ setV8ObjectPropertyAsString(keyframe3, "offset", "0");
+
+ jsKeyframes.append(Dictionary(keyframe1, m_isolate));
+ jsKeyframes.append(Dictionary(keyframe2, m_isolate));
+ jsKeyframes.append(Dictionary(keyframe3, m_isolate));
+
+ RefPtrWillBeRawPtr<AnimationEffect> animationEffect ALLOW_UNUSED = EffectInput::convert(element.get(), jsKeyframes, exceptionState);
+ EXPECT_TRUE(exceptionState.hadException());
+ EXPECT_EQ(InvalidModificationError, exceptionState.code());
+}
+
+}
diff --git a/chromium/third_party/WebKit/Source/core/animation/ElementAnimation.cpp b/chromium/third_party/WebKit/Source/core/animation/ElementAnimation.cpp
deleted file mode 100644
index 0beb346f7d6..00000000000
--- a/chromium/third_party/WebKit/Source/core/animation/ElementAnimation.cpp
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "core/animation/ElementAnimation.h"
-
-#include "core/animation/DocumentTimeline.h"
-#include "core/css/RuntimeCSSEnabled.h"
-#include "core/css/resolver/StyleResolver.h"
-#include "wtf/text/StringBuilder.h"
-#include <algorithm>
-
-namespace WebCore {
-
-CSSPropertyID ElementAnimation::camelCaseCSSPropertyNameToID(const String& propertyName)
-{
- if (propertyName.find('-') != kNotFound)
- return CSSPropertyInvalid;
-
- StringBuilder builder;
- size_t position = 0;
- size_t end;
- while ((end = propertyName.find(isASCIIUpper, position)) != kNotFound) {
- builder.append(propertyName.substring(position, end - position) + "-" + toASCIILower((propertyName)[end]));
- position = end + 1;
- }
- builder.append(propertyName.substring(position));
- // Doesn't handle prefixed properties.
- CSSPropertyID id = cssPropertyID(builder.toString());
- return id;
-}
-
-void ElementAnimation::animate(Element* element, Vector<Dictionary> keyframeDictionaryVector, double duration)
-{
- ASSERT(RuntimeEnabledFeatures::webAnimationsAPIEnabled());
-
- // FIXME: This test will not be neccessary once resolution of keyframe values occurs at
- // animation application time.
- if (!element->inActiveDocument())
- return;
- element->document().updateStyleIfNeeded();
- if (!element->renderer())
- return;
-
- startAnimation(element, keyframeDictionaryVector, duration);
-}
-
-void ElementAnimation::startAnimation(Element* element, Vector<Dictionary> keyframeDictionaryVector, double duration)
-{
- KeyframeAnimationEffect::KeyframeVector keyframes;
- Vector<RefPtr<MutableStylePropertySet> > propertySetVector;
-
- for (size_t i = 0; i < keyframeDictionaryVector.size(); ++i) {
- RefPtr<MutableStylePropertySet> propertySet = MutableStylePropertySet::create();
- propertySetVector.append(propertySet);
-
- RefPtr<Keyframe> keyframe = Keyframe::create();
- keyframes.append(keyframe);
-
- double offset;
- if (keyframeDictionaryVector[i].get("offset", offset)) {
- keyframe->setOffset(offset);
- } else {
- // FIXME: Web Animations CSS engine does not yet implement handling of
- // keyframes without specified offsets. This check can be removed when
- // that funcitonality is implemented.
- ASSERT_NOT_REACHED();
- return;
- }
-
- String compositeString;
- keyframeDictionaryVector[i].get("composite", compositeString);
- if (compositeString == "add")
- keyframe->setComposite(AnimationEffect::CompositeAdd);
-
- Vector<String> keyframeProperties;
- keyframeDictionaryVector[i].getOwnPropertyNames(keyframeProperties);
-
- for (size_t j = 0; j < keyframeProperties.size(); ++j) {
- String property = keyframeProperties[j];
- CSSPropertyID id = camelCaseCSSPropertyNameToID(property);
-
- // FIXME: There is no way to store invalid properties or invalid values
- // in a Keyframe object, so for now I just skip over them. Eventually we
- // will need to support getFrames(), which should return exactly the
- // keyframes that were input through the API. We will add a layer to wrap
- // KeyframeAnimationEffect, store input keyframes and implement getFrames.
- if (id == CSSPropertyInvalid || !CSSAnimations::isAnimatableProperty(id))
- continue;
-
- String value;
- keyframeDictionaryVector[i].get(property, value);
- propertySet->setProperty(id, value);
- }
- }
-
- // FIXME: Replace this with code that just parses, when that code is available.
- RefPtr<KeyframeAnimationEffect> effect = StyleResolver::createKeyframeAnimationEffect(*element, propertySetVector, keyframes);
-
- // FIXME: Totally hardcoded Timing for now. Will handle timing parameters later.
- Timing timing;
- // FIXME: Currently there is no way to tell whether or not an iterationDuration
- // has been specified (becauser the default argument is 0). So any animation
- // created using Element.animate() will have a timing with hasIterationDuration()
- // == true.
- timing.hasIterationDuration = true;
- timing.iterationDuration = std::max<double>(duration, 0);
-
- RefPtr<Animation> animation = Animation::create(element, effect, timing);
- DocumentTimeline* timeline = element->document().timeline();
- ASSERT(timeline);
- timeline->play(animation.get());
-}
-
-} // namespace WebCore
diff --git a/chromium/third_party/WebKit/Source/core/animation/ElementAnimation.h b/chromium/third_party/WebKit/Source/core/animation/ElementAnimation.h
index cfc8f6999fa..5f60e2e79ee 100644
--- a/chromium/third_party/WebKit/Source/core/animation/ElementAnimation.h
+++ b/chromium/third_party/WebKit/Source/core/animation/ElementAnimation.h
@@ -31,22 +31,71 @@
#ifndef ElementAnimation_h
#define ElementAnimation_h
-#include "bindings/v8/Dictionary.h"
-#include "core/css/CSSParser.h"
+#include "core/animation/Animation.h"
+#include "core/animation/AnimationTimeline.h"
+#include "core/animation/EffectInput.h"
+#include "core/animation/TimingInput.h"
+#include "core/dom/Document.h"
+#include "core/dom/Element.h"
+#include "platform/RuntimeEnabledFeatures.h"
namespace WebCore {
-class Element;
+class Dictionary;
class ElementAnimation {
public:
- static CSSPropertyID camelCaseCSSPropertyNameToID(const String& propertyName);
- static void animate(Element*, Vector<Dictionary> keyframesDictionaryVector, double duration = 0);
+ static AnimationPlayer* animate(Element& element, PassRefPtrWillBeRawPtr<AnimationEffect> effect, const Dictionary& timingInputDictionary)
+ {
+ return animateInternal(element, effect, TimingInput::convert(timingInputDictionary));
+ }
-private:
- static void startAnimation(Element*, Vector<Dictionary> keyframesDictionaryVector, double duration = 0);
+ static AnimationPlayer* animate(Element& element, PassRefPtrWillBeRawPtr<AnimationEffect> effect, double duration)
+ {
+ return animateInternal(element, effect, TimingInput::convert(duration));
+ }
+
+ static AnimationPlayer* animate(Element& element, PassRefPtrWillBeRawPtr<AnimationEffect> effect)
+ {
+ return animateInternal(element, effect, Timing());
+ }
+
+ static AnimationPlayer* animate(Element& element, const Vector<Dictionary>& keyframeDictionaryVector, const Dictionary& timingInputDictionary, ExceptionState& exceptionState)
+ {
+ RefPtrWillBeRawPtr<AnimationEffect> effect = EffectInput::convert(&element, keyframeDictionaryVector, exceptionState);
+ if (exceptionState.hadException())
+ return 0;
+ ASSERT(effect);
+ return animateInternal(element, effect.release(), TimingInput::convert(timingInputDictionary));
+ }
- friend class AnimationElementAnimationTest;
+ static AnimationPlayer* animate(Element& element, const Vector<Dictionary>& keyframeDictionaryVector, double duration, ExceptionState& exceptionState)
+ {
+ RefPtrWillBeRawPtr<AnimationEffect> effect = EffectInput::convert(&element, keyframeDictionaryVector, exceptionState);
+ if (exceptionState.hadException())
+ return 0;
+ ASSERT(effect);
+ return animateInternal(element, effect.release(), TimingInput::convert(duration));
+ }
+
+ static AnimationPlayer* animate(Element& element, const Vector<Dictionary>& keyframeDictionaryVector, ExceptionState& exceptionState)
+ {
+ RefPtrWillBeRawPtr<AnimationEffect> effect = EffectInput::convert(&element, keyframeDictionaryVector, exceptionState);
+ if (exceptionState.hadException())
+ return 0;
+ ASSERT(effect);
+ return animateInternal(element, effect.release(), Timing());
+ }
+
+private:
+ static AnimationPlayer* animateInternal(Element& element, PassRefPtrWillBeRawPtr<AnimationEffect> effect, const Timing& timing)
+ {
+ if (RuntimeEnabledFeatures::webAnimationsElementAnimateEnabled()) {
+ RefPtrWillBeRawPtr<Animation> animation = Animation::create(&element, effect, timing);
+ return element.document().timeline().play(animation.get());
+ }
+ return 0;
+ }
};
} // namespace WebCore
diff --git a/chromium/third_party/WebKit/Source/core/animation/ElementAnimation.idl b/chromium/third_party/WebKit/Source/core/animation/ElementAnimation.idl
index e191d950bc0..f524939ba45 100644
--- a/chromium/third_party/WebKit/Source/core/animation/ElementAnimation.idl
+++ b/chromium/third_party/WebKit/Source/core/animation/ElementAnimation.idl
@@ -28,6 +28,12 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+// http://www.w3.org/TR/web-animations/#idl-def-Element
+// FIXME: move to Animatable
+// http://dev.w3.org/fxtf/web-animations/#idl-def-Animatable
+
partial interface Element {
- [RuntimeEnabled=WebAnimationsAPI] void animate(sequence<Dictionary> keyframes, optional double duration);
-}; \ No newline at end of file
+ // FIXME: needs support for union types http://crbug.com/240176
+ // AnimationPlayer animate((AnimationEffect or sequence<Dictionary>)? effect, optional (double or Dictionary) timing);
+ [Custom, RaisesException] AnimationPlayer animate(object effect, optional object timing);
+};
diff --git a/chromium/third_party/WebKit/Source/core/animation/ElementAnimationTest.cpp b/chromium/third_party/WebKit/Source/core/animation/ElementAnimationTest.cpp
deleted file mode 100644
index bb3f0d4f0ad..00000000000
--- a/chromium/third_party/WebKit/Source/core/animation/ElementAnimationTest.cpp
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * Copyright (c) 2013, Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "core/animation/ElementAnimation.h"
-
-#include "core/animation/AnimatableLength.h"
-#include "core/animation/Animation.h"
-#include "core/animation/AnimationClock.h"
-#include "core/animation/DocumentTimeline.h"
-#include "core/animation/KeyframeAnimationEffect.h"
-#include "core/dom/Document.h"
-#include "core/dom/Element.h"
-
-#include <gtest/gtest.h>
-
-namespace WebCore {
-
-namespace {
-
-v8::Handle<v8::Value> stringToV8Value(String string)
-{
- return v8::Handle<v8::Value>::Cast(v8String(v8::Isolate::GetCurrent(), string));
-}
-
-void setV8ObjectProperty(v8::Handle<v8::Object> object, String name, String value)
-{
- object->Set(stringToV8Value(name), stringToV8Value(value));
-}
-
-} // namespace
-
-class AnimationElementAnimationTest : public ::testing::Test {
-protected:
- virtual void SetUp()
- {
- document = Document::create();
- document->animationClock().resetTimeForTesting();
- element = document->createElement("foo", ASSERT_NO_EXCEPTION);
- document->timeline()->setZeroTime(0);
- ASSERT_EQ(0, document->timeline()->currentTime());
- }
-
- RefPtr<Document> document;
- RefPtr<Element> element;
-
- void startAnimation(Element* element, Vector<Dictionary> keyframesDictionaryVector)
- {
- ElementAnimation::startAnimation(element, keyframesDictionaryVector);
- }
-
- void startAnimationWithSpecifiedDuration(Element* element, Vector<Dictionary> keyframesDictionaryVector, double duration)
- {
- ElementAnimation::startAnimation(element, keyframesDictionaryVector, duration);
- }
-};
-
-TEST_F(AnimationElementAnimationTest, CanStartAnAnimation)
-{
- v8::Isolate* isolate = v8::Isolate::GetCurrent();
- v8::HandleScope scope(isolate);
- v8::Local<v8::Context> context = v8::Context::New(isolate);
- v8::Context::Scope contextScope(context);
-
- Vector<Dictionary> jsKeyframes;
- v8::Handle<v8::Object> keyframe1 = v8::Object::New();
- v8::Handle<v8::Object> keyframe2 = v8::Object::New();
-
- setV8ObjectProperty(keyframe1, "width", "100px");
- setV8ObjectProperty(keyframe1, "offset", "0");
- setV8ObjectProperty(keyframe2, "width", "0px");
- setV8ObjectProperty(keyframe2, "offset", "1");
-
- jsKeyframes.append(Dictionary(keyframe1, isolate));
- jsKeyframes.append(Dictionary(keyframe2, isolate));
-
- String value1;
- ASSERT_TRUE(jsKeyframes[0].get("width", value1));
- ASSERT_EQ("100px", value1);
-
- String value2;
- ASSERT_TRUE(jsKeyframes[1].get("width", value2));
- ASSERT_EQ("0px", value2);
-
- startAnimationWithSpecifiedDuration(element.get(), jsKeyframes, 0);
-
- Player* player = document->timeline()->players().at(0).get();
-
- Animation* animation = toAnimation(player->source());
-
- Element* target = animation->target();
- EXPECT_EQ(*element.get(), *target);
-
- const KeyframeAnimationEffect::KeyframeVector keyframes =
- toKeyframeAnimationEffect(animation->effect())->getFrames();
-
- EXPECT_EQ(0, keyframes[0]->offset());
- EXPECT_EQ(1, keyframes[1]->offset());
-
- const AnimatableValue* keyframe1Width = keyframes[0]->propertyValue(CSSPropertyWidth);
- const AnimatableValue* keyframe2Width = keyframes[1]->propertyValue(CSSPropertyWidth);
- ASSERT(keyframe1Width);
- ASSERT(keyframe2Width);
-
- EXPECT_TRUE(keyframe1Width->isLength());
- EXPECT_TRUE(keyframe2Width->isLength());
-
- EXPECT_EQ("100px", toAnimatableLength(keyframe1Width)->toCSSValue()->cssText());
- EXPECT_EQ("0px", toAnimatableLength(keyframe2Width)->toCSSValue()->cssText());
-}
-
-TEST_F(AnimationElementAnimationTest, ParseCamelCasePropertyNames)
-{
- EXPECT_EQ(CSSPropertyInvalid, ElementAnimation::camelCaseCSSPropertyNameToID(String("line-height")));
- EXPECT_EQ(CSSPropertyLineHeight, ElementAnimation::camelCaseCSSPropertyNameToID(String("lineHeight")));
- EXPECT_EQ(CSSPropertyBorderTopWidth, ElementAnimation::camelCaseCSSPropertyNameToID(String("borderTopWidth")));
- EXPECT_EQ(CSSPropertyWidth, ElementAnimation::camelCaseCSSPropertyNameToID(String("width")));
- EXPECT_EQ(CSSPropertyInvalid, ElementAnimation::camelCaseCSSPropertyNameToID(String("Width")));
- EXPECT_EQ(CSSPropertyInvalid, ElementAnimation::camelCaseCSSPropertyNameToID(String("-webkit-transform")));
- EXPECT_EQ(CSSPropertyInvalid, ElementAnimation::camelCaseCSSPropertyNameToID(String("webkitTransform")));
- EXPECT_EQ(CSSPropertyInvalid, ElementAnimation::camelCaseCSSPropertyNameToID(String("cssFloat")));
-}
-
-TEST_F(AnimationElementAnimationTest, CanSetDuration)
-{
- v8::Isolate* isolate = v8::Isolate::GetCurrent();
- v8::HandleScope scope(isolate);
- v8::Local<v8::Context> context = v8::Context::New(isolate);
- v8::Context::Scope contextScope(context);
-
- Vector<Dictionary, 0> jsKeyframes;
- double duration = 2;
-
- startAnimationWithSpecifiedDuration(element.get(), jsKeyframes, duration);
-
- Player* player = document->timeline()->players().at(0).get();
-
- EXPECT_TRUE(player->source()->specified().hasIterationDuration);
- EXPECT_EQ(duration, player->source()->specified().iterationDuration);
-}
-
-TEST_F(AnimationElementAnimationTest, CanOmitSpecifiedDuration)
-{
- v8::Isolate* isolate = v8::Isolate::GetCurrent();
- v8::HandleScope scope(isolate);
- v8::Local<v8::Context> context = v8::Context::New(isolate);
- v8::Context::Scope contextScope(context);
-
- Vector<Dictionary, 0> jsKeyframes;
-
- startAnimation(element.get(), jsKeyframes);
-
- Player* player = document->timeline()->players().at(0).get();
-
- // FIXME: This is correct for the moment, as using c++ default arguments means
- // there is no way to tell whether a duration has been specified by the user.
- // Once we implment timing object arguments we should be able to tell, and this
- // check should be changed to EXPECT_FALSE.
- EXPECT_TRUE(player->source()->specified().hasIterationDuration);
- EXPECT_EQ(0, player->source()->specified().iterationDuration);
-}
-
-TEST_F(AnimationElementAnimationTest, ClipNegativeDurationToZero)
-{
- v8::Isolate* isolate = v8::Isolate::GetCurrent();
- v8::HandleScope scope(isolate);
- v8::Local<v8::Context> context = v8::Context::New(isolate);
- v8::Context::Scope contextScope(context);
-
- Vector<Dictionary, 0> jsKeyframes;
- double duration = -2;
-
- startAnimationWithSpecifiedDuration(element.get(), jsKeyframes, duration);
-
- Player* player = document->timeline()->players().at(0).get();
-
- EXPECT_TRUE(player->source()->specified().hasIterationDuration);
- EXPECT_EQ(0, player->source()->specified().iterationDuration);
-}
-
-} // namespace WebCore
diff --git a/chromium/third_party/WebKit/Source/core/animation/InertAnimation.cpp b/chromium/third_party/WebKit/Source/core/animation/InertAnimation.cpp
index 3cb21505300..3ba61c06a8c 100644
--- a/chromium/third_party/WebKit/Source/core/animation/InertAnimation.cpp
+++ b/chromium/third_party/WebKit/Source/core/animation/InertAnimation.cpp
@@ -30,37 +30,43 @@
#include "config.h"
#include "core/animation/InertAnimation.h"
+#include "core/animation/interpolation/Interpolation.h"
namespace WebCore {
-PassRefPtr<InertAnimation> InertAnimation::create(PassRefPtr<AnimationEffect> effect, const Timing& timing, bool paused)
+PassRefPtrWillBeRawPtr<InertAnimation> InertAnimation::create(PassRefPtrWillBeRawPtr<AnimationEffect> effect, const Timing& timing, bool paused)
{
- return adoptRef(new InertAnimation(effect, timing, paused));
+ return adoptRefWillBeNoop(new InertAnimation(effect, timing, paused));
}
-InertAnimation::InertAnimation(PassRefPtr<AnimationEffect> effect, const Timing& timing, bool paused)
- : TimedItem(timing)
+InertAnimation::InertAnimation(PassRefPtrWillBeRawPtr<AnimationEffect> effect, const Timing& timing, bool paused)
+ : AnimationNode(timing)
, m_effect(effect)
, m_paused(paused)
{
}
-PassOwnPtr<AnimationEffect::CompositableValueList> InertAnimation::sample()
+PassOwnPtrWillBeRawPtr<WillBeHeapVector<RefPtrWillBeMember<Interpolation> > > InertAnimation::sample(double inheritedTime)
{
- updateInheritedTime(0);
+ updateInheritedTime(inheritedTime, TimingUpdateOnDemand);
if (!isInEffect())
return nullptr;
double iteration = currentIteration();
ASSERT(iteration >= 0);
// FIXME: Handle iteration values which overflow int.
- return m_effect->sample(static_cast<int>(iteration), timeFraction());
+ return m_effect->sample(static_cast<int>(iteration), timeFraction(), iterationDuration());
}
-
-double InertAnimation::calculateTimeToEffectChange(double, double) const
+double InertAnimation::calculateTimeToEffectChange(bool, double, double) const
{
return std::numeric_limits<double>::infinity();
}
+void InertAnimation::trace(Visitor* visitor)
+{
+ visitor->trace(m_effect);
+ AnimationNode::trace(visitor);
+}
+
} // namespace WebCore
diff --git a/chromium/third_party/WebKit/Source/core/animation/InertAnimation.h b/chromium/third_party/WebKit/Source/core/animation/InertAnimation.h
index a52ba532ec6..633ad5030ca 100644
--- a/chromium/third_party/WebKit/Source/core/animation/InertAnimation.h
+++ b/chromium/third_party/WebKit/Source/core/animation/InertAnimation.h
@@ -32,27 +32,27 @@
#define InertAnimation_h
#include "core/animation/AnimationEffect.h"
-#include "core/animation/TimedItem.h"
+#include "core/animation/AnimationNode.h"
#include "wtf/RefPtr.h"
namespace WebCore {
-class InertAnimation FINAL : public TimedItem {
-
+class InertAnimation FINAL : public AnimationNode {
public:
- static PassRefPtr<InertAnimation> create(PassRefPtr<AnimationEffect>, const Timing&, bool paused);
- PassOwnPtr<AnimationEffect::CompositableValueList> sample();
+ static PassRefPtrWillBeRawPtr<InertAnimation> create(PassRefPtrWillBeRawPtr<AnimationEffect>, const Timing&, bool paused);
+ PassOwnPtrWillBeRawPtr<WillBeHeapVector<RefPtrWillBeMember<Interpolation> > > sample(double inheritedTime);
AnimationEffect* effect() const { return m_effect.get(); }
bool paused() const { return m_paused; }
+ virtual void trace(Visitor*);
+
protected:
- virtual bool updateChildrenAndEffects() const OVERRIDE { return false; };
- virtual void willDetach() OVERRIDE { };
- virtual double calculateTimeToEffectChange(double inheritedTime, double timeToNextIteration) const OVERRIDE FINAL;
+ virtual void updateChildrenAndEffects() const OVERRIDE { }
+ virtual double calculateTimeToEffectChange(bool forwards, double inheritedTime, double timeToNextIteration) const OVERRIDE;
private:
- InertAnimation(PassRefPtr<AnimationEffect>, const Timing&, bool paused);
- RefPtr<AnimationEffect> m_effect;
+ InertAnimation(PassRefPtrWillBeRawPtr<AnimationEffect>, const Timing&, bool paused);
+ RefPtrWillBeMember<AnimationEffect> m_effect;
bool m_paused;
};
diff --git a/chromium/third_party/WebKit/Source/core/animation/InterpolableValue.cpp b/chromium/third_party/WebKit/Source/core/animation/InterpolableValue.cpp
new file mode 100644
index 00000000000..e1b43a9345c
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/InterpolableValue.cpp
@@ -0,0 +1,75 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "config.h"
+#include "core/animation/InterpolableValue.h"
+
+namespace WebCore {
+
+DEFINE_EMPTY_DESTRUCTOR_WILL_BE_REMOVED(InterpolableValue);
+
+PassOwnPtrWillBeRawPtr<InterpolableValue> InterpolableNumber::interpolate(const InterpolableValue &to, const double progress) const
+{
+ const InterpolableNumber* toNumber = toInterpolableNumber(&to);
+ if (!progress)
+ return create(m_value);
+ if (progress == 1)
+ return create(toNumber->m_value);
+ return create(m_value * (1 - progress) + toNumber->m_value * progress);
+}
+
+PassOwnPtrWillBeRawPtr<InterpolableValue> InterpolableBool::interpolate(const InterpolableValue &to, const double progress) const
+{
+ if (progress < 0.5) {
+ return clone();
+ }
+ return to.clone();
+}
+
+PassOwnPtrWillBeRawPtr<InterpolableValue> InterpolableList::interpolate(const InterpolableValue &to, const double progress) const
+{
+ const InterpolableList* toList = toInterpolableList(&to);
+ ASSERT(toList->m_size == m_size);
+
+ if (!progress) {
+ return create(*this);
+ }
+ if (progress == 1) {
+ return InterpolableList::create(*toList);
+ }
+
+ OwnPtrWillBeRawPtr<InterpolableList> result = create(m_size);
+ for (size_t i = 0; i < m_size; i++) {
+ ASSERT(m_values[i]);
+ ASSERT(toList->m_values[i]);
+ result->set(i, m_values[i]->interpolate(*(toList->m_values[i]), progress));
+ }
+ return result.release();
+}
+
+void InterpolableList::trace(Visitor* visitor)
+{
+#if ENABLE_OILPAN
+ visitor->trace(m_values);
+#endif
+ InterpolableValue::trace(visitor);
+}
+
+PassOwnPtrWillBeRawPtr<InterpolableValue> InterpolableAnimatableValue::interpolate(const InterpolableValue &other, const double percentage) const
+{
+ const InterpolableAnimatableValue *otherValue = toInterpolableAnimatableValue(&other);
+ if (!percentage)
+ return create(m_value);
+ if (percentage == 1)
+ return create(otherValue->m_value);
+ return create(AnimatableValue::interpolate(m_value.get(), otherValue->m_value.get(), percentage));
+}
+
+void InterpolableAnimatableValue::trace(Visitor* visitor)
+{
+ visitor->trace(m_value);
+ InterpolableValue::trace(visitor);
+}
+
+}
diff --git a/chromium/third_party/WebKit/Source/core/animation/InterpolableValue.h b/chromium/third_party/WebKit/Source/core/animation/InterpolableValue.h
new file mode 100644
index 00000000000..75484cf12b1
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/InterpolableValue.h
@@ -0,0 +1,167 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef InterpolableValue_h
+#define InterpolableValue_h
+
+#include "core/animation/AnimatableValue.h"
+#include "wtf/OwnPtr.h"
+#include "wtf/PassOwnPtr.h"
+#include "wtf/Vector.h"
+
+namespace WebCore {
+
+class InterpolableValue : public NoBaseWillBeGarbageCollected<InterpolableValue> {
+ DECLARE_EMPTY_VIRTUAL_DESTRUCTOR_WILL_BE_REMOVED(InterpolableValue);
+public:
+ virtual bool isNumber() const { return false; }
+ virtual bool isBool() const { return false; }
+ virtual bool isList() const { return false; }
+ virtual bool isAnimatableValue() const { return false; }
+
+ virtual PassOwnPtrWillBeRawPtr<InterpolableValue> clone() const = 0;
+
+ virtual void trace(Visitor*) { }
+
+private:
+ virtual PassOwnPtrWillBeRawPtr<InterpolableValue> interpolate(const InterpolableValue &to, const double progress) const = 0;
+
+ friend class Interpolation;
+
+ // Keep interpolate private, but allow calls within the hierarchy without
+ // knowledge of type.
+ friend class DeferredLegacyStyleInterpolation;
+ friend class InterpolableNumber;
+ friend class InterpolableBool;
+ friend class InterpolableList;
+};
+
+class InterpolableNumber : public InterpolableValue {
+public:
+ static PassOwnPtrWillBeRawPtr<InterpolableNumber> create(double value)
+ {
+ return adoptPtrWillBeNoop(new InterpolableNumber(value));
+ }
+
+ virtual bool isNumber() const OVERRIDE FINAL { return true; }
+ double value() const { return m_value; }
+ virtual PassOwnPtrWillBeRawPtr<InterpolableValue> clone() const OVERRIDE FINAL { return create(m_value); }
+
+ virtual void trace(Visitor* visitor) OVERRIDE { InterpolableValue::trace(visitor); }
+
+private:
+ virtual PassOwnPtrWillBeRawPtr<InterpolableValue> interpolate(const InterpolableValue &to, const double progress) const OVERRIDE FINAL;
+ double m_value;
+
+ explicit InterpolableNumber(double value)
+ : m_value(value)
+ {
+ }
+
+};
+
+class InterpolableBool : public InterpolableValue {
+public:
+ static PassOwnPtrWillBeRawPtr<InterpolableBool> create(bool value)
+ {
+ return adoptPtrWillBeNoop(new InterpolableBool(value));
+ }
+
+ virtual bool isBool() const OVERRIDE FINAL { return true; }
+ bool value() const { return m_value; }
+ virtual PassOwnPtrWillBeRawPtr<InterpolableValue> clone() const OVERRIDE FINAL { return create(m_value); }
+
+ virtual void trace(Visitor* visitor) OVERRIDE { InterpolableValue::trace(visitor); }
+
+private:
+ virtual PassOwnPtrWillBeRawPtr<InterpolableValue> interpolate(const InterpolableValue &to, const double progress) const OVERRIDE FINAL;
+ bool m_value;
+
+ explicit InterpolableBool(bool value)
+ : m_value(value)
+ {
+ }
+
+};
+
+class InterpolableList : public InterpolableValue {
+public:
+ static PassOwnPtrWillBeRawPtr<InterpolableList> create(const InterpolableList &other)
+ {
+ return adoptPtrWillBeNoop(new InterpolableList(other));
+ }
+
+ static PassOwnPtrWillBeRawPtr<InterpolableList> create(size_t size)
+ {
+ return adoptPtrWillBeNoop(new InterpolableList(size));
+ }
+
+ virtual bool isList() const OVERRIDE FINAL { return true; }
+ void set(size_t position, PassOwnPtrWillBeRawPtr<InterpolableValue> value)
+ {
+ ASSERT(position < m_size);
+ m_values[position] = value;
+ }
+ const InterpolableValue* get(size_t position) const
+ {
+ ASSERT(position < m_size);
+ return m_values[position].get();
+ }
+ size_t length() const { return m_size; }
+ virtual PassOwnPtrWillBeRawPtr<InterpolableValue> clone() const OVERRIDE FINAL { return create(*this); }
+
+ virtual void trace(Visitor*) OVERRIDE;
+
+private:
+ virtual PassOwnPtrWillBeRawPtr<InterpolableValue> interpolate(const InterpolableValue &other, const double progress) const OVERRIDE FINAL;
+ explicit InterpolableList(size_t size)
+ : m_size(size)
+ , m_values(m_size)
+ {
+ }
+
+ InterpolableList(const InterpolableList& other)
+ : m_size(other.m_size)
+ , m_values(m_size)
+ {
+ for (size_t i = 0; i < m_size; i++)
+ set(i, other.m_values[i]->clone());
+ }
+
+ size_t m_size;
+ WillBeHeapVector<OwnPtrWillBeMember<InterpolableValue> > m_values;
+};
+
+// FIXME: Remove this when we can.
+class InterpolableAnimatableValue : public InterpolableValue {
+public:
+ static PassOwnPtrWillBeRawPtr<InterpolableAnimatableValue> create(PassRefPtrWillBeRawPtr<AnimatableValue> value)
+ {
+ return adoptPtrWillBeNoop(new InterpolableAnimatableValue(value));
+ }
+
+ virtual bool isAnimatableValue() const OVERRIDE FINAL { return true; }
+ AnimatableValue* value() const { return m_value.get(); }
+ virtual PassOwnPtrWillBeRawPtr<InterpolableValue> clone() const OVERRIDE FINAL { return create(m_value); }
+
+ virtual void trace(Visitor*) OVERRIDE;
+
+private:
+ virtual PassOwnPtrWillBeRawPtr<InterpolableValue> interpolate(const InterpolableValue &other, const double progress) const OVERRIDE FINAL;
+ RefPtrWillBeMember<AnimatableValue> m_value;
+
+ InterpolableAnimatableValue(PassRefPtrWillBeRawPtr<AnimatableValue> value)
+ : m_value(value)
+ {
+ }
+};
+
+DEFINE_TYPE_CASTS(InterpolableNumber, InterpolableValue, value, value->isNumber(), value.isNumber());
+DEFINE_TYPE_CASTS(InterpolableBool, InterpolableValue, value, value->isBool(), value.isBool());
+DEFINE_TYPE_CASTS(InterpolableList, InterpolableValue, value, value->isList(), value.isList());
+DEFINE_TYPE_CASTS(InterpolableAnimatableValue, InterpolableValue, value, value->isAnimatableValue(), value.isAnimatableValue());
+
+}
+
+#endif
diff --git a/chromium/third_party/WebKit/Source/core/animation/InterpolableValueTest.cpp b/chromium/third_party/WebKit/Source/core/animation/InterpolableValueTest.cpp
new file mode 100644
index 00000000000..69ed8f6084f
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/InterpolableValueTest.cpp
@@ -0,0 +1,105 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "config.h"
+#include "core/animation/InterpolableValue.h"
+
+#include "core/animation/interpolation/Interpolation.h"
+
+#include <gtest/gtest.h>
+
+namespace WebCore {
+
+class AnimationInterpolableValueTest : public ::testing::Test {
+protected:
+ InterpolableValue* interpolationValue(Interpolation& interpolation)
+ {
+ return interpolation.getCachedValueForTesting();
+ }
+
+ double interpolateNumbers(double a, double b, double progress)
+ {
+ RefPtrWillBeRawPtr<Interpolation> i = Interpolation::create(InterpolableNumber::create(a), InterpolableNumber::create(b));
+ i->interpolate(0, progress);
+ return toInterpolableNumber(interpolationValue(*i.get()))->value();
+ }
+
+ bool interpolateBools(bool a, bool b, double progress)
+ {
+ RefPtrWillBeRawPtr<Interpolation> i = Interpolation::create(InterpolableBool::create(a), InterpolableBool::create(b));
+ i->interpolate(0, progress);
+ return toInterpolableBool(interpolationValue(*i.get()))->value();
+ }
+
+ PassRefPtrWillBeRawPtr<Interpolation> interpolateLists(PassOwnPtrWillBeRawPtr<InterpolableList> listA, PassOwnPtrWillBeRawPtr<InterpolableList> listB, double progress)
+ {
+ RefPtrWillBeRawPtr<Interpolation> i = Interpolation::create(listA, listB);
+ i->interpolate(0, progress);
+ return i;
+ }
+};
+
+TEST_F(AnimationInterpolableValueTest, InterpolateNumbers)
+{
+ EXPECT_FLOAT_EQ(126, interpolateNumbers(42, 0, -2));
+ EXPECT_FLOAT_EQ(42, interpolateNumbers(42, 0, 0));
+ EXPECT_FLOAT_EQ(29.4f, interpolateNumbers(42, 0, 0.3));
+ EXPECT_FLOAT_EQ(21, interpolateNumbers(42, 0, 0.5));
+ EXPECT_FLOAT_EQ(0, interpolateNumbers(42, 0, 1));
+ EXPECT_FLOAT_EQ(-21, interpolateNumbers(42, 0, 1.5));
+}
+
+TEST_F(AnimationInterpolableValueTest, InterpolateBools)
+{
+ EXPECT_FALSE(interpolateBools(false, true, -1));
+ EXPECT_FALSE(interpolateBools(false, true, 0));
+ EXPECT_FALSE(interpolateBools(false, true, 0.3));
+ EXPECT_TRUE(interpolateBools(false, true, 0.5));
+ EXPECT_TRUE(interpolateBools(false, true, 1));
+ EXPECT_TRUE(interpolateBools(false, true, 2));
+}
+
+TEST_F(AnimationInterpolableValueTest, SimpleList)
+{
+ OwnPtrWillBeRawPtr<InterpolableList> listA = InterpolableList::create(3);
+ listA->set(0, InterpolableNumber::create(0));
+ listA->set(1, InterpolableNumber::create(42));
+ listA->set(2, InterpolableNumber::create(20.5));
+
+ OwnPtrWillBeRawPtr<InterpolableList> listB = InterpolableList::create(3);
+ listB->set(0, InterpolableNumber::create(100));
+ listB->set(1, InterpolableNumber::create(-200));
+ listB->set(2, InterpolableNumber::create(300));
+
+ RefPtrWillBeRawPtr<Interpolation> i = interpolateLists(listA.release(), listB.release(), 0.3);
+ InterpolableList* outList = toInterpolableList(interpolationValue(*i.get()));
+ EXPECT_FLOAT_EQ(30, toInterpolableNumber(outList->get(0))->value());
+ EXPECT_FLOAT_EQ(-30.6f, toInterpolableNumber(outList->get(1))->value());
+ EXPECT_FLOAT_EQ(104.35f, toInterpolableNumber(outList->get(2))->value());
+}
+
+TEST_F(AnimationInterpolableValueTest, NestedList)
+{
+ OwnPtrWillBeRawPtr<InterpolableList> listA = InterpolableList::create(3);
+ listA->set(0, InterpolableNumber::create(0));
+ OwnPtrWillBeRawPtr<InterpolableList> subListA = InterpolableList::create(1);
+ subListA->set(0, InterpolableNumber::create(100));
+ listA->set(1, subListA.release());
+ listA->set(2, InterpolableBool::create(false));
+
+ OwnPtrWillBeRawPtr<InterpolableList> listB = InterpolableList::create(3);
+ listB->set(0, InterpolableNumber::create(100));
+ OwnPtrWillBeRawPtr<InterpolableList> subListB = InterpolableList::create(1);
+ subListB->set(0, InterpolableNumber::create(50));
+ listB->set(1, subListB.release());
+ listB->set(2, InterpolableBool::create(true));
+
+ RefPtrWillBeRawPtr<Interpolation> i = interpolateLists(listA.release(), listB.release(), 0.5);
+ InterpolableList* outList = toInterpolableList(interpolationValue(*i.get()));
+ EXPECT_FLOAT_EQ(50, toInterpolableNumber(outList->get(0))->value());
+ EXPECT_FLOAT_EQ(75, toInterpolableNumber(toInterpolableList(outList->get(1))->get(0))->value());
+ EXPECT_TRUE(toInterpolableBool(outList->get(2))->value());
+}
+
+}
diff --git a/chromium/third_party/WebKit/Source/core/animation/InterpolationEffect.cpp b/chromium/third_party/WebKit/Source/core/animation/InterpolationEffect.cpp
new file mode 100644
index 00000000000..c03fbab782c
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/InterpolationEffect.cpp
@@ -0,0 +1,42 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "config.h"
+#include "core/animation/InterpolationEffect.h"
+
+namespace WebCore {
+
+PassOwnPtrWillBeRawPtr<WillBeHeapVector<RefPtrWillBeMember<Interpolation> > > InterpolationEffect::getActiveInterpolations(double fraction, double iterationDuration) const
+{
+
+ WillBeHeapVector<RefPtrWillBeMember<Interpolation> >* result = new WillBeHeapVector<RefPtrWillBeMember<Interpolation> >();
+
+ for (size_t i = 0; i < m_interpolations.size(); ++i) {
+ const InterpolationRecord* record = m_interpolations[i].get();
+ if (fraction >= record->m_applyFrom && fraction < record->m_applyTo) {
+ RefPtrWillBeRawPtr<Interpolation> interpolation = record->m_interpolation;
+ double localFraction = (fraction - record->m_start) / (record->m_end - record->m_start);
+ if (record->m_easing)
+ localFraction = record->m_easing->evaluate(localFraction, accuracyForDuration(iterationDuration));
+ interpolation->interpolate(0, localFraction);
+ result->append(interpolation);
+ }
+ }
+
+ return adoptPtrWillBeNoop(result);
+}
+
+void InterpolationEffect::InterpolationRecord::trace(Visitor* visitor)
+{
+ visitor->trace(m_interpolation);
+}
+
+void InterpolationEffect::trace(Visitor* visitor)
+{
+#if ENABLE_OILPAN
+ visitor->trace(m_interpolations);
+#endif
+}
+
+}
diff --git a/chromium/third_party/WebKit/Source/core/animation/InterpolationEffect.h b/chromium/third_party/WebKit/Source/core/animation/InterpolationEffect.h
new file mode 100644
index 00000000000..c189f86deca
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/InterpolationEffect.h
@@ -0,0 +1,66 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef InterpolationEffect_h
+#define InterpolationEffect_h
+
+#include "core/animation/interpolation/Interpolation.h"
+#include "platform/animation/TimingFunction.h"
+#include "wtf/PassOwnPtr.h"
+#include "wtf/RefCounted.h"
+
+namespace WebCore {
+
+class InterpolationEffect : public RefCountedWillBeGarbageCollected<InterpolationEffect> {
+public:
+ static PassRefPtrWillBeRawPtr<InterpolationEffect> create() { return adoptRefWillBeNoop(new InterpolationEffect()); }
+
+ PassOwnPtrWillBeRawPtr<WillBeHeapVector<RefPtrWillBeMember<Interpolation> > > getActiveInterpolations(double fraction, double iterationDuration) const;
+
+ void addInterpolation(PassRefPtrWillBeRawPtr<Interpolation> interpolation, PassRefPtr<TimingFunction> easing, double start, double end, double applyFrom, double applyTo)
+ {
+ m_interpolations.append(InterpolationRecord::create(interpolation, easing, start, end, applyFrom, applyTo));
+ }
+
+ void trace(Visitor*);
+
+private:
+ InterpolationEffect()
+ {
+ }
+
+ class InterpolationRecord : public NoBaseWillBeGarbageCollectedFinalized<InterpolationRecord> {
+ public:
+ RefPtrWillBeMember<Interpolation> m_interpolation;
+ RefPtr<TimingFunction> m_easing;
+ double m_start;
+ double m_end;
+ double m_applyFrom;
+ double m_applyTo;
+
+ static PassOwnPtrWillBeRawPtr<InterpolationRecord> create(PassRefPtrWillBeRawPtr<Interpolation> interpolation, PassRefPtr<TimingFunction> easing, double start, double end, double applyFrom, double applyTo)
+ {
+ return adoptPtrWillBeNoop(new InterpolationRecord(interpolation, easing, start, end, applyFrom, applyTo));
+ }
+
+ void trace(Visitor*);
+
+ private:
+ InterpolationRecord(PassRefPtrWillBeRawPtr<Interpolation> interpolation, PassRefPtr<TimingFunction> easing, double start, double end, double applyFrom, double applyTo)
+ : m_interpolation(interpolation)
+ , m_easing(easing)
+ , m_start(start)
+ , m_end(end)
+ , m_applyFrom(applyFrom)
+ , m_applyTo(applyTo)
+ {
+ }
+ };
+
+ WillBeHeapVector<OwnPtrWillBeMember<InterpolationRecord> > m_interpolations;
+};
+
+}
+
+#endif
diff --git a/chromium/third_party/WebKit/Source/core/animation/InterpolationEffectTest.cpp b/chromium/third_party/WebKit/Source/core/animation/InterpolationEffectTest.cpp
new file mode 100644
index 00000000000..8b84b755d05
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/InterpolationEffectTest.cpp
@@ -0,0 +1,98 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "config.h"
+#include "core/animation/InterpolationEffect.h"
+
+#include <gtest/gtest.h>
+
+namespace {
+
+const double duration = 1.0;
+
+} // namespace
+
+namespace WebCore {
+
+class AnimationInterpolationEffectTest : public ::testing::Test {
+protected:
+ InterpolableValue* interpolationValue(Interpolation& interpolation)
+ {
+ return interpolation.getCachedValueForTesting();
+ }
+
+ double getInterpolableNumber(PassRefPtrWillBeRawPtr<Interpolation> value)
+ {
+ return toInterpolableNumber(interpolationValue(*value.get()))->value();
+ }
+};
+
+TEST_F(AnimationInterpolationEffectTest, SingleInterpolation)
+{
+ RefPtrWillBeRawPtr<InterpolationEffect> interpolationEffect = InterpolationEffect::create();
+ interpolationEffect->addInterpolation(Interpolation::create(InterpolableNumber::create(0), InterpolableNumber::create(10)),
+ RefPtr<TimingFunction>(), 0, 1, -1, 2);
+
+ OwnPtrWillBeRawPtr<WillBeHeapVector<RefPtrWillBeMember<Interpolation> > > activeInterpolations = interpolationEffect->getActiveInterpolations(-2, duration);
+ EXPECT_EQ(0ul, activeInterpolations->size());
+
+ activeInterpolations = interpolationEffect->getActiveInterpolations(-0.5, duration);
+ EXPECT_EQ(1ul, activeInterpolations->size());
+ EXPECT_EQ(-5, getInterpolableNumber(activeInterpolations->at(0)));
+
+ activeInterpolations = interpolationEffect->getActiveInterpolations(0.5, duration);
+ EXPECT_EQ(1ul, activeInterpolations->size());
+ EXPECT_FLOAT_EQ(5, getInterpolableNumber(activeInterpolations->at(0)));
+
+ activeInterpolations = interpolationEffect->getActiveInterpolations(1.5, duration);
+ EXPECT_EQ(1ul, activeInterpolations->size());
+ EXPECT_FLOAT_EQ(15, getInterpolableNumber(activeInterpolations->at(0)));
+
+ activeInterpolations = interpolationEffect->getActiveInterpolations(3, duration);
+ EXPECT_EQ(0ul, activeInterpolations->size());
+}
+
+TEST_F(AnimationInterpolationEffectTest, MultipleInterpolations)
+{
+ RefPtrWillBeRawPtr<InterpolationEffect> interpolationEffect = InterpolationEffect::create();
+ interpolationEffect->addInterpolation(Interpolation::create(InterpolableNumber::create(10), InterpolableNumber::create(15)),
+ RefPtr<TimingFunction>(), 1, 2, 1, 3);
+ interpolationEffect->addInterpolation(Interpolation::create(InterpolableNumber::create(0), InterpolableNumber::create(1)),
+ LinearTimingFunction::shared(), 0, 1, 0, 1);
+ interpolationEffect->addInterpolation(Interpolation::create(InterpolableNumber::create(1), InterpolableNumber::create(6)),
+ CubicBezierTimingFunction::preset(CubicBezierTimingFunction::Ease), 0.5, 1.5, 0.5, 1.5);
+
+ OwnPtrWillBeRawPtr<WillBeHeapVector<RefPtrWillBeMember<Interpolation> > > activeInterpolations = interpolationEffect->getActiveInterpolations(-0.5, duration);
+ EXPECT_EQ(0ul, activeInterpolations->size());
+
+ activeInterpolations = interpolationEffect->getActiveInterpolations(0, duration);
+ EXPECT_EQ(1ul, activeInterpolations->size());
+ EXPECT_FLOAT_EQ(0, getInterpolableNumber(activeInterpolations->at(0)));
+
+ activeInterpolations = interpolationEffect->getActiveInterpolations(0.5, duration);
+ EXPECT_EQ(2ul, activeInterpolations->size());
+ EXPECT_FLOAT_EQ(0.5f, getInterpolableNumber(activeInterpolations->at(0)));
+ EXPECT_FLOAT_EQ(1, getInterpolableNumber(activeInterpolations->at(1)));
+
+ activeInterpolations = interpolationEffect->getActiveInterpolations(1, duration);
+ EXPECT_EQ(2ul, activeInterpolations->size());
+ EXPECT_FLOAT_EQ(10, getInterpolableNumber(activeInterpolations->at(0)));
+ EXPECT_FLOAT_EQ(5.0282884f, getInterpolableNumber(activeInterpolations->at(1)));
+
+ activeInterpolations = interpolationEffect->getActiveInterpolations(1, duration * 1000);
+ EXPECT_EQ(2ul, activeInterpolations->size());
+ EXPECT_FLOAT_EQ(10, getInterpolableNumber(activeInterpolations->at(0)));
+ EXPECT_FLOAT_EQ(5.0120168f, getInterpolableNumber(activeInterpolations->at(1)));
+
+ activeInterpolations = interpolationEffect->getActiveInterpolations(1.5, duration);
+ EXPECT_EQ(1ul, activeInterpolations->size());
+ EXPECT_FLOAT_EQ(12.5f, getInterpolableNumber(activeInterpolations->at(0)));
+
+ activeInterpolations = interpolationEffect->getActiveInterpolations(2, duration);
+ EXPECT_EQ(1ul, activeInterpolations->size());
+ EXPECT_FLOAT_EQ(15, getInterpolableNumber(activeInterpolations->at(0)));
+}
+
+}
+
diff --git a/chromium/third_party/WebKit/Source/core/animation/Keyframe.h b/chromium/third_party/WebKit/Source/core/animation/Keyframe.h
new file mode 100644
index 00000000000..1f47c906117
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/Keyframe.h
@@ -0,0 +1,102 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef Keyframe_h
+#define Keyframe_h
+
+#include "core/CSSPropertyNames.h"
+#include "core/animation/AnimatableValue.h"
+#include "core/animation/AnimationEffect.h"
+#include "core/animation/AnimationNode.h"
+
+namespace WebCore {
+
+typedef HashSet<CSSPropertyID> PropertySet;
+
+class Element;
+
+// FIXME: Make Keyframe immutable
+class Keyframe : public RefCountedWillBeGarbageCollectedFinalized<Keyframe> {
+public:
+ virtual ~Keyframe() { }
+
+ void setOffset(double offset) { m_offset = offset; }
+ double offset() const { return m_offset; }
+
+ void setComposite(AnimationEffect::CompositeOperation composite) { m_composite = composite; }
+ AnimationEffect::CompositeOperation composite() const { return m_composite; }
+
+ void setEasing(PassRefPtr<TimingFunction> easing) { m_easing = easing; }
+ TimingFunction* easing() const { return m_easing.get(); }
+
+ static bool compareOffsets(const RefPtrWillBeMember<Keyframe>& a, const RefPtrWillBeMember<Keyframe>& b)
+ {
+ return a->offset() < b->offset();
+ }
+
+ virtual PropertySet properties() const = 0;
+
+ virtual PassRefPtrWillBeRawPtr<Keyframe> clone() const = 0;
+ PassRefPtrWillBeRawPtr<Keyframe> cloneWithOffset(double offset) const
+ {
+ RefPtrWillBeRawPtr<Keyframe> theClone = clone();
+ theClone->setOffset(offset);
+ return theClone.release();
+ }
+
+ virtual bool isAnimatableValueKeyframe() const { return false; }
+ virtual bool isStringKeyframe() const { return false; }
+
+ virtual void trace(Visitor*) { }
+
+ class PropertySpecificKeyframe : public NoBaseWillBeGarbageCollectedFinalized<PropertySpecificKeyframe> {
+ public:
+ virtual ~PropertySpecificKeyframe() { }
+ double offset() const { return m_offset; }
+ TimingFunction* easing() const { return m_easing.get(); }
+ AnimationEffect::CompositeOperation composite() const { return m_composite; }
+ virtual PassOwnPtrWillBeRawPtr<PropertySpecificKeyframe> cloneWithOffset(double offset) const = 0;
+
+ virtual const PassRefPtrWillBeRawPtr<AnimatableValue> getAnimatableValue() const = 0;
+
+ virtual bool isAnimatableValuePropertySpecificKeyframe() const { return false; }
+ virtual bool isStringPropertySpecificKeyframe() const { return false; }
+
+ virtual PassOwnPtrWillBeRawPtr<PropertySpecificKeyframe> neutralKeyframe(double offset, PassRefPtr<TimingFunction> easing) const = 0;
+ virtual PassRefPtrWillBeRawPtr<Interpolation> createInterpolation(CSSPropertyID, WebCore::Keyframe::PropertySpecificKeyframe* end, Element*) const = 0;
+
+ virtual void trace(Visitor*) { }
+
+ protected:
+ PropertySpecificKeyframe(double offset, PassRefPtr<TimingFunction> easing, AnimationEffect::CompositeOperation);
+
+ double m_offset;
+ RefPtr<TimingFunction> m_easing;
+ AnimationEffect::CompositeOperation m_composite;
+ };
+
+ virtual PassOwnPtrWillBeRawPtr<PropertySpecificKeyframe> createPropertySpecificKeyframe(CSSPropertyID) const = 0;
+
+protected:
+ Keyframe()
+ : m_offset(nullValue())
+ , m_composite(AnimationEffect::CompositeReplace)
+ , m_easing(LinearTimingFunction::shared())
+ {
+ }
+ Keyframe(double offset, AnimationEffect::CompositeOperation composite, PassRefPtr<TimingFunction> easing)
+ : m_offset(offset)
+ , m_composite(composite)
+ , m_easing(easing)
+ {
+ }
+
+ double m_offset;
+ AnimationEffect::CompositeOperation m_composite;
+ RefPtr<TimingFunction> m_easing;
+};
+
+}
+
+#endif
diff --git a/chromium/third_party/WebKit/Source/core/animation/KeyframeAnimationEffect.cpp b/chromium/third_party/WebKit/Source/core/animation/KeyframeAnimationEffect.cpp
deleted file mode 100644
index dd6ffa3a832..00000000000
--- a/chromium/third_party/WebKit/Source/core/animation/KeyframeAnimationEffect.cpp
+++ /dev/null
@@ -1,367 +0,0 @@
-/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "core/animation/KeyframeAnimationEffect.h"
-
-#include "core/animation/TimedItem.h"
-#include "wtf/text/StringHash.h"
-
-namespace {
-
-using namespace WebCore;
-
-class ReplaceCompositableValue : public AnimationEffect::CompositableValue {
-public:
- static PassRefPtr<ReplaceCompositableValue> create(const AnimatableValue* value)
- {
- return adoptRef(new ReplaceCompositableValue(value));
- }
- virtual bool dependsOnUnderlyingValue() const
- {
- return false;
- }
- virtual PassRefPtr<AnimatableValue> compositeOnto(const AnimatableValue* underlyingValue) const
- {
- return PassRefPtr<AnimatableValue>(m_value);
- }
-private:
- ReplaceCompositableValue(const AnimatableValue* value)
- : m_value(const_cast<AnimatableValue*>(value))
- {
- }
- RefPtr<AnimatableValue> m_value;
-};
-
-class AddCompositableValue : public AnimationEffect::CompositableValue {
-public:
- static PassRefPtr<AddCompositableValue> create(const AnimatableValue* value)
- {
- return adoptRef(new AddCompositableValue(value));
- }
- virtual bool dependsOnUnderlyingValue() const
- {
- return true;
- }
- virtual PassRefPtr<AnimatableValue> compositeOnto(const AnimatableValue* underlyingValue) const
- {
- return AnimatableValue::add(underlyingValue, m_value.get());
- }
-private:
- AddCompositableValue(const AnimatableValue* value)
- : m_value(const_cast<AnimatableValue*>(value))
- {
- }
- RefPtr<AnimatableValue> m_value;
-};
-
-class BlendedCompositableValue : public AnimationEffect::CompositableValue {
-public:
- static PassRefPtr<BlendedCompositableValue> create(const AnimationEffect::CompositableValue* before, const AnimationEffect::CompositableValue* after, double fraction)
- {
- return adoptRef(new BlendedCompositableValue(before, after, fraction));
- }
- virtual bool dependsOnUnderlyingValue() const
- {
- return m_dependsOnUnderlyingValue;
- }
- virtual PassRefPtr<AnimatableValue> compositeOnto(const AnimatableValue* underlyingValue) const
- {
- return AnimatableValue::interpolate(m_before->compositeOnto(underlyingValue).get(), m_after->compositeOnto(underlyingValue).get(), m_fraction);
- }
-private:
- BlendedCompositableValue(const AnimationEffect::CompositableValue* before, const AnimationEffect::CompositableValue* after, double fraction)
- : m_before(const_cast<AnimationEffect::CompositableValue*>(before))
- , m_after(const_cast<AnimationEffect::CompositableValue*>(after))
- , m_fraction(fraction)
- , m_dependsOnUnderlyingValue(before->dependsOnUnderlyingValue() || after->dependsOnUnderlyingValue())
- { }
- RefPtr<AnimationEffect::CompositableValue> m_before;
- RefPtr<AnimationEffect::CompositableValue> m_after;
- double m_fraction;
- bool m_dependsOnUnderlyingValue;
-};
-
-} // namespace
-
-
-namespace WebCore {
-
-Keyframe::Keyframe()
- : m_offset(nullValue())
- , m_composite(AnimationEffect::CompositeReplace)
-{ }
-
-Keyframe::Keyframe(const Keyframe& copyFrom)
- : m_offset(copyFrom.m_offset)
- , m_composite(copyFrom.m_composite)
-{
- for (PropertyValueMap::const_iterator iter = copyFrom.m_propertyValues.begin(); iter != copyFrom.m_propertyValues.end(); ++iter)
- setPropertyValue(iter->key, iter->value.get());
-}
-
-void Keyframe::setPropertyValue(CSSPropertyID property, const AnimatableValue* value)
-{
- m_propertyValues.add(property, const_cast<AnimatableValue*>(value));
-}
-
-void Keyframe::clearPropertyValue(CSSPropertyID property)
-{
- m_propertyValues.remove(property);
-}
-
-const AnimatableValue* Keyframe::propertyValue(CSSPropertyID property) const
-{
- ASSERT(m_propertyValues.contains(property));
- return m_propertyValues.get(property);
-}
-
-PropertySet Keyframe::properties() const
-{
- // This is not used in time-critical code, so we probably don't need to
- // worry about caching this result.
- PropertySet properties;
- for (PropertyValueMap::const_iterator iter = m_propertyValues.begin(); iter != m_propertyValues.end(); ++iter)
- properties.add(*iter.keys());
- return properties;
-}
-
-PassRefPtr<Keyframe> Keyframe::cloneWithOffset(double offset) const
-{
- RefPtr<Keyframe> theClone = clone();
- theClone->setOffset(offset);
- return theClone.release();
-}
-
-KeyframeAnimationEffect::KeyframeAnimationEffect(const KeyframeVector& keyframes)
- : m_keyframes(keyframes)
-{
-}
-
-PropertySet KeyframeAnimationEffect::properties() const
-{
- PropertySet result;
- const KeyframeVector& frames = getFrames();
- if (!frames.size()) {
- return result;
- }
- result = frames[0]->properties();
- for (size_t i = 1; i < frames.size(); i++) {
- PropertySet extras = frames[i]->properties();
- for (PropertySet::const_iterator it = extras.begin(); it != extras.end(); ++it) {
- result.add(*it);
- }
- }
- return result;
-}
-
-PassOwnPtr<AnimationEffect::CompositableValueList> KeyframeAnimationEffect::sample(int iteration, double fraction) const
-{
- ASSERT(iteration >= 0);
- ASSERT(!isNull(fraction));
- const_cast<KeyframeAnimationEffect*>(this)->ensureKeyframeGroups();
- OwnPtr<CompositableValueList> map = adoptPtr(new CompositableValueList());
- for (KeyframeGroupMap::const_iterator iter = m_keyframeGroups->begin(); iter != m_keyframeGroups->end(); ++iter)
- map->append(std::make_pair(iter->key, iter->value->sample(iteration, fraction)));
- return map.release();
-}
-
-KeyframeAnimationEffect::KeyframeVector KeyframeAnimationEffect::normalizedKeyframes() const
-{
- KeyframeVector keyframes = m_keyframes;
-
- // Set offsets at 0.0 and 1.0 at ends if unset.
- if (keyframes.size() >= 2) {
- Keyframe* firstKeyframe = keyframes.first().get();
- if (isNull(firstKeyframe->offset()))
- firstKeyframe->setOffset(0.0);
- }
- if (keyframes.size() >= 1) {
- Keyframe* lastKeyframe = keyframes.last().get();
- if (lastKeyframe && isNull(lastKeyframe->offset()))
- lastKeyframe->setOffset(1.0);
- }
-
- // FIXME: Distribute offsets where missing.
- for (KeyframeVector::iterator iter = keyframes.begin(); iter != keyframes.end(); ++iter)
- ASSERT(!isNull((*iter)->offset()));
-
- // Sort by offset.
- std::stable_sort(keyframes.begin(), keyframes.end(), Keyframe::compareOffsets);
- return keyframes;
-}
-
-void KeyframeAnimationEffect::ensureKeyframeGroups() const
-{
- if (m_keyframeGroups)
- return;
-
- m_keyframeGroups = adoptPtr(new KeyframeGroupMap);
- const KeyframeVector& keyframes = normalizedKeyframes();
- for (KeyframeVector::const_iterator keyframeIter = keyframes.begin(); keyframeIter != keyframes.end(); ++keyframeIter) {
- const Keyframe* keyframe = keyframeIter->get();
- PropertySet keyframeProperties = keyframe->properties();
- for (PropertySet::const_iterator propertyIter = keyframeProperties.begin(); propertyIter != keyframeProperties.end(); ++propertyIter) {
- CSSPropertyID property = *propertyIter;
- KeyframeGroupMap::iterator groupIter = m_keyframeGroups->find(property);
- if (groupIter == m_keyframeGroups->end()) {
- KeyframeGroupMap::AddResult result = m_keyframeGroups->add(property, adoptPtr(new PropertySpecificKeyframeGroup));
- ASSERT(result.isNewEntry);
- groupIter = result.iterator;
- }
- groupIter->value->appendKeyframe(adoptPtr(
- new PropertySpecificKeyframe(keyframe->offset(), keyframe->propertyValue(property), keyframe->composite())));
- }
- }
-
- // Add synthetic keyframes.
- for (KeyframeGroupMap::iterator iter = m_keyframeGroups->begin(); iter != m_keyframeGroups->end(); ++iter) {
- iter->value->addSyntheticKeyframeIfRequired();
- iter->value->removeRedundantKeyframes();
- }
-}
-
-
-KeyframeAnimationEffect::PropertySpecificKeyframe::PropertySpecificKeyframe(double offset, const AnimatableValue* value, CompositeOperation composite)
- : m_offset(offset)
- , m_value(composite == AnimationEffect::CompositeReplace ?
- static_cast<PassRefPtr<CompositableValue> >(ReplaceCompositableValue::create(value)) :
- static_cast<PassRefPtr<CompositableValue> >(AddCompositableValue::create(value)))
-{
-}
-
-KeyframeAnimationEffect::PropertySpecificKeyframe::PropertySpecificKeyframe(double offset, PassRefPtr<CompositableValue> value)
- : m_offset(offset)
- , m_value(value)
-{
- ASSERT(!isNull(m_offset));
-}
-
-PassOwnPtr<KeyframeAnimationEffect::PropertySpecificKeyframe> KeyframeAnimationEffect::PropertySpecificKeyframe::cloneWithOffset(double offset) const
-{
- return adoptPtr(new PropertySpecificKeyframe(offset, PassRefPtr<CompositableValue>(m_value)));
-}
-
-
-void KeyframeAnimationEffect::PropertySpecificKeyframeGroup::appendKeyframe(PassOwnPtr<PropertySpecificKeyframe> keyframe)
-{
- ASSERT(m_keyframes.isEmpty() || m_keyframes.last()->offset() <= keyframe->offset());
- m_keyframes.append(keyframe);
-}
-
-void KeyframeAnimationEffect::PropertySpecificKeyframeGroup::removeRedundantKeyframes()
-{
- // As an optimization, removes keyframes in the following categories, as
- // they will never be used by sample().
- // - End keyframes with the same offset as their neighbor
- // - Interior keyframes with the same offset as both their neighbors
- // Note that synthetic keyframes must be added before this method is
- // called.
- ASSERT(m_keyframes.size() >= 2);
- for (int i = m_keyframes.size() - 1; i >= 0; --i) {
- double offset = m_keyframes[i]->offset();
- bool hasSameOffsetAsPreviousNeighbor = !i || m_keyframes[i - 1]->offset() == offset;
- bool hasSameOffsetAsNextNeighbor = i == static_cast<int>(m_keyframes.size() - 1) || m_keyframes[i + 1]->offset() == offset;
- if (hasSameOffsetAsPreviousNeighbor && hasSameOffsetAsNextNeighbor)
- m_keyframes.remove(i);
- }
- ASSERT(m_keyframes.size() >= 2);
-}
-
-void KeyframeAnimationEffect::PropertySpecificKeyframeGroup::addSyntheticKeyframeIfRequired()
-{
- ASSERT(!m_keyframes.isEmpty());
- double offset = m_keyframes.first()->offset();
- bool allOffsetsEqual = true;
- for (PropertySpecificKeyframeVector::const_iterator iter = m_keyframes.begin() + 1; iter != m_keyframes.end(); ++iter) {
- if ((*iter)->offset() != offset) {
- allOffsetsEqual = false;
- break;
- }
- }
- if (!allOffsetsEqual)
- return;
-
- if (!offset)
- appendKeyframe(m_keyframes.first()->cloneWithOffset(1.0));
- else
- m_keyframes.insert(0, adoptPtr(new PropertySpecificKeyframe(0.0, AnimatableValue::neutralValue(), CompositeAdd)));
-}
-
-PassRefPtr<AnimationEffect::CompositableValue> KeyframeAnimationEffect::PropertySpecificKeyframeGroup::sample(int iteration, double offset) const
-{
- // FIXME: Implement accumulation.
- ASSERT_UNUSED(iteration, iteration >= 0);
- ASSERT(!isNull(offset));
-
- // Bail if offset is null, as this can lead to buffer overflow below.
- if (isNull(offset))
- return const_cast<CompositableValue*>(m_keyframes.first()->value());
-
- double minimumOffset = m_keyframes.first()->offset();
- double maximumOffset = m_keyframes.last()->offset();
- ASSERT(minimumOffset != maximumOffset);
-
- PropertySpecificKeyframeVector::const_iterator before;
- PropertySpecificKeyframeVector::const_iterator after;
-
- // Note that this algorithm is simpler than that in the spec because we
- // have removed keyframes with equal offsets in
- // removeRedundantKeyframes().
- if (offset < minimumOffset) {
- before = m_keyframes.begin();
- after = before + 1;
- ASSERT((*before)->offset() > offset);
- ASSERT((*after)->offset() > offset);
- } else if (offset >= maximumOffset) {
- after = m_keyframes.end() - 1;
- before = after - 1;
- ASSERT((*before)->offset() < offset);
- ASSERT((*after)->offset() <= offset);
- } else {
- // FIXME: This is inefficient for large numbers of keyframes. Consider
- // using binary search.
- after = m_keyframes.begin();
- while ((*after)->offset() <= offset)
- ++after;
- before = after - 1;
- ASSERT((*before)->offset() <= offset);
- ASSERT((*after)->offset() > offset);
- }
-
- if ((*before)->offset() == offset)
- return const_cast<CompositableValue*>((*before)->value());
- if ((*after)->offset() == offset)
- return const_cast<CompositableValue*>((*after)->value());
- return BlendedCompositableValue::create((*before)->value(), (*after)->value(),
- (offset - (*before)->offset()) / ((*after)->offset() - (*before)->offset()));
-}
-
-} // namespace
diff --git a/chromium/third_party/WebKit/Source/core/animation/KeyframeAnimationEffect.h b/chromium/third_party/WebKit/Source/core/animation/KeyframeAnimationEffect.h
deleted file mode 100644
index ee784299dc4..00000000000
--- a/chromium/third_party/WebKit/Source/core/animation/KeyframeAnimationEffect.h
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef KeyframeAnimationEffect_h
-#define KeyframeAnimationEffect_h
-
-#include "core/animation/AnimatableValue.h"
-#include "core/animation/AnimationEffect.h"
-#include "wtf/HashMap.h"
-#include "wtf/HashSet.h"
-#include "wtf/PassOwnPtr.h"
-#include "wtf/PassRefPtr.h"
-#include "wtf/RefCounted.h"
-#include "wtf/Vector.h"
-
-namespace WebCore {
-
-typedef HashSet<CSSPropertyID> PropertySet;
-
-// Represents the keyframes set through the API.
-class Keyframe : public RefCounted<Keyframe> {
-public:
- static PassRefPtr<Keyframe> create()
- {
- return adoptRef(new Keyframe);
- }
- static bool compareOffsets(const RefPtr<Keyframe>& a, const RefPtr<Keyframe>& b)
- {
- return a->offset() < b->offset();
- }
- void setOffset(double offset) { m_offset = offset; }
- double offset() const { return m_offset; }
- void setComposite(AnimationEffect::CompositeOperation composite) { m_composite = composite; }
- AnimationEffect::CompositeOperation composite() const { return m_composite; }
- void setPropertyValue(CSSPropertyID, const AnimatableValue*);
- void clearPropertyValue(CSSPropertyID);
- const AnimatableValue* propertyValue(CSSPropertyID) const;
- PropertySet properties() const;
- PassRefPtr<Keyframe> clone() const { return adoptRef(new Keyframe(*this)); }
- PassRefPtr<Keyframe> cloneWithOffset(double offset) const;
-private:
- Keyframe();
- Keyframe(const Keyframe&);
- double m_offset;
- AnimationEffect::CompositeOperation m_composite;
- typedef HashMap<CSSPropertyID, RefPtr<AnimatableValue> > PropertyValueMap;
- PropertyValueMap m_propertyValues;
-};
-
-class KeyframeAnimationEffect : public AnimationEffect {
-public:
- class PropertySpecificKeyframe;
- typedef Vector<RefPtr<Keyframe> > KeyframeVector;
- typedef Vector<OwnPtr<KeyframeAnimationEffect::PropertySpecificKeyframe> > PropertySpecificKeyframeVector;
- // FIXME: Implement accumulation.
- static PassRefPtr<KeyframeAnimationEffect> create(const KeyframeVector& keyframes)
- {
- return adoptRef(new KeyframeAnimationEffect(keyframes));
- }
-
- virtual bool affects(CSSPropertyID property) OVERRIDE
- {
- ensureKeyframeGroups();
- return m_keyframeGroups->contains(property);
- }
-
- // AnimationEffect implementation.
- virtual PassOwnPtr<CompositableValueList> sample(int iteration, double fraction) const OVERRIDE;
-
- // FIXME: Implement setFrames()
- const KeyframeVector& getFrames() const { return m_keyframes; }
-
- virtual bool isKeyframeAnimationEffect() const OVERRIDE { return true; }
-
- PropertySet properties() const;
-
- class PropertySpecificKeyframe {
- public:
- PropertySpecificKeyframe(double offset, const AnimatableValue*, CompositeOperation);
- double offset() const { return m_offset; }
- const CompositableValue* value() const { return m_value.get(); }
- PassOwnPtr<PropertySpecificKeyframe> cloneWithOffset(double offset) const;
- private:
- // Used by cloneWithOffset().
- PropertySpecificKeyframe(double offset, PassRefPtr<CompositableValue>);
- double m_offset;
- RefPtr<CompositableValue> m_value;
- };
-
- class PropertySpecificKeyframeGroup {
- public:
- void appendKeyframe(PassOwnPtr<PropertySpecificKeyframe>);
- PassRefPtr<CompositableValue> sample(int iteration, double offset) const;
- const PropertySpecificKeyframeVector& keyframes() const { return m_keyframes; }
- private:
- PropertySpecificKeyframeVector m_keyframes;
- void removeRedundantKeyframes();
- void addSyntheticKeyframeIfRequired();
-
- friend class KeyframeAnimationEffect;
- };
-
- const PropertySpecificKeyframeVector& getPropertySpecificKeyframes(CSSPropertyID id) const
- {
- ensureKeyframeGroups();
- return m_keyframeGroups->get(id)->keyframes();
- }
-
-private:
- KeyframeAnimationEffect(const KeyframeVector& keyframes);
-
- KeyframeVector normalizedKeyframes() const;
- // Lazily computes the groups of property-specific keyframes.
- void ensureKeyframeGroups() const;
-
- KeyframeVector m_keyframes;
- // The spec describes filtering the normalized keyframes at sampling time
- // to get the 'property-specific keyframes'. For efficiency, we cache the
- // property-specific lists.
- typedef HashMap<CSSPropertyID, OwnPtr<PropertySpecificKeyframeGroup> > KeyframeGroupMap;
- mutable OwnPtr<KeyframeGroupMap> m_keyframeGroups;
-};
-
-DEFINE_TYPE_CASTS(KeyframeAnimationEffect, AnimationEffect, value, value->isKeyframeAnimationEffect(), value.isKeyframeAnimationEffect());
-
-} // namespace WebCore
-
-#endif // KeyframeAnimationEffect_h
diff --git a/chromium/third_party/WebKit/Source/core/animation/KeyframeAnimationEffectTest.cpp b/chromium/third_party/WebKit/Source/core/animation/KeyframeAnimationEffectTest.cpp
deleted file mode 100644
index 4a493bd4f27..00000000000
--- a/chromium/third_party/WebKit/Source/core/animation/KeyframeAnimationEffectTest.cpp
+++ /dev/null
@@ -1,379 +0,0 @@
-/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "core/animation/KeyframeAnimationEffect.h"
-
-#include "core/animation/AnimatableLength.h"
-#include "core/animation/AnimatableUnknown.h"
-#include "core/css/CSSPrimitiveValue.h"
-#include <gtest/gtest.h>
-
-using namespace WebCore;
-
-namespace {
-
-AnimatableValue* unknownAnimatableValue(double n)
-{
- return AnimatableUnknown::create(CSSPrimitiveValue::create(n, CSSPrimitiveValue::CSS_UNKNOWN).get()).leakRef();
-}
-
-AnimatableValue* pixelAnimatableValue(double n)
-{
- return AnimatableLength::create(CSSPrimitiveValue::create(n, CSSPrimitiveValue::CSS_PX).get()).leakRef();
-}
-
-KeyframeAnimationEffect::KeyframeVector keyframesAtZeroAndOne(AnimatableValue* zeroValue, AnimatableValue* oneValue)
-{
- KeyframeAnimationEffect::KeyframeVector keyframes(2);
- keyframes[0] = Keyframe::create();
- keyframes[0]->setOffset(0.0);
- keyframes[0]->setPropertyValue(CSSPropertyLeft, zeroValue);
- keyframes[1] = Keyframe::create();
- keyframes[1]->setOffset(1.0);
- keyframes[1]->setPropertyValue(CSSPropertyLeft, oneValue);
- return keyframes;
-}
-
-void expectDoubleValue(double expectedValue, PassRefPtr<AnimatableValue> value)
-{
- ASSERT_TRUE(value->isLength() || value->isUnknown());
-
- double actualValue;
- if (value->isLength())
- actualValue = toCSSPrimitiveValue(toAnimatableLength(value.get())->toCSSValue().get())->getDoubleValue();
- else
- actualValue = toCSSPrimitiveValue(toAnimatableUnknown(value.get())->toCSSValue().get())->getDoubleValue();
-
- EXPECT_FLOAT_EQ(static_cast<float>(expectedValue), actualValue);
-}
-
-
-TEST(AnimationKeyframeAnimationEffectTest, BasicOperation)
-{
- KeyframeAnimationEffect::KeyframeVector keyframes = keyframesAtZeroAndOne(unknownAnimatableValue(3.0), unknownAnimatableValue(5.0));
- RefPtr<KeyframeAnimationEffect> effect = KeyframeAnimationEffect::create(keyframes);
- OwnPtr<AnimationEffect::CompositableValueList> values = effect->sample(0, 0.6);
- ASSERT_EQ(1UL, values->size());
- EXPECT_EQ(CSSPropertyLeft, values->at(0).first);
- expectDoubleValue(5.0, values->at(0).second->compositeOnto(unknownAnimatableValue(7.0)));
-}
-
-TEST(AnimationKeyframeAnimationEffectTest, CompositeReplaceNonInterpolable)
-{
- KeyframeAnimationEffect::KeyframeVector keyframes = keyframesAtZeroAndOne(unknownAnimatableValue(3.0), unknownAnimatableValue(5.0));
- keyframes[0]->setComposite(AnimationEffect::CompositeReplace);
- keyframes[1]->setComposite(AnimationEffect::CompositeReplace);
- RefPtr<KeyframeAnimationEffect> effect = KeyframeAnimationEffect::create(keyframes);
- expectDoubleValue(5.0, effect->sample(0, 0.6)->at(0).second->compositeOnto(unknownAnimatableValue(7.0)));
-}
-
-TEST(AnimationKeyframeAnimationEffectTest, CompositeReplace)
-{
- KeyframeAnimationEffect::KeyframeVector keyframes = keyframesAtZeroAndOne(pixelAnimatableValue(3.0), pixelAnimatableValue(5.0));
- keyframes[0]->setComposite(AnimationEffect::CompositeReplace);
- keyframes[1]->setComposite(AnimationEffect::CompositeReplace);
- RefPtr<KeyframeAnimationEffect> effect = KeyframeAnimationEffect::create(keyframes);
- expectDoubleValue(3.0 * 0.4 + 5.0 * 0.6, effect->sample(0, 0.6)->at(0).second->compositeOnto(unknownAnimatableValue(7.0)));
-}
-
-TEST(AnimationKeyframeAnimationEffectTest, CompositeAdd)
-{
- KeyframeAnimationEffect::KeyframeVector keyframes = keyframesAtZeroAndOne(pixelAnimatableValue(3.0), pixelAnimatableValue(5.0));
- keyframes[0]->setComposite(AnimationEffect::CompositeAdd);
- keyframes[1]->setComposite(AnimationEffect::CompositeAdd);
- RefPtr<KeyframeAnimationEffect> effect = KeyframeAnimationEffect::create(keyframes);
- expectDoubleValue((7.0 + 3.0) * 0.4 + (7.0 + 5.0) * 0.6, effect->sample(0, 0.6)->at(0).second->compositeOnto(pixelAnimatableValue(7.0)));
-}
-
-TEST(AnimationKeyframeAnimationEffectTest, ExtrapolateReplaceNonInterpolable)
-{
- KeyframeAnimationEffect::KeyframeVector keyframes = keyframesAtZeroAndOne(unknownAnimatableValue(3.0), unknownAnimatableValue(5.0));
- RefPtr<KeyframeAnimationEffect> effect = KeyframeAnimationEffect::create(keyframes);
- keyframes[0]->setComposite(AnimationEffect::CompositeReplace);
- keyframes[1]->setComposite(AnimationEffect::CompositeReplace);
- expectDoubleValue(5.0, effect->sample(0, 1.6)->at(0).second->compositeOnto(unknownAnimatableValue(7.0)));
-}
-
-TEST(AnimationKeyframeAnimationEffectTest, ExtrapolateReplace)
-{
- KeyframeAnimationEffect::KeyframeVector keyframes = keyframesAtZeroAndOne(pixelAnimatableValue(3.0), pixelAnimatableValue(5.0));
- RefPtr<KeyframeAnimationEffect> effect = KeyframeAnimationEffect::create(keyframes);
- keyframes[0]->setComposite(AnimationEffect::CompositeReplace);
- keyframes[1]->setComposite(AnimationEffect::CompositeReplace);
- expectDoubleValue(3.0 * -0.6 + 5.0 * 1.6, effect->sample(0, 1.6)->at(0).second->compositeOnto(pixelAnimatableValue(7.0)));
-}
-
-TEST(AnimationKeyframeAnimationEffectTest, ExtrapolateAdd)
-{
- KeyframeAnimationEffect::KeyframeVector keyframes = keyframesAtZeroAndOne(pixelAnimatableValue(3.0), pixelAnimatableValue(5.0));
- keyframes[0]->setComposite(AnimationEffect::CompositeAdd);
- keyframes[1]->setComposite(AnimationEffect::CompositeAdd);
- RefPtr<KeyframeAnimationEffect> effect = KeyframeAnimationEffect::create(keyframes);
- expectDoubleValue((7.0 + 3.0) * -0.6 + (7.0 + 5.0) * 1.6, effect->sample(0, 1.6)->at(0).second->compositeOnto(pixelAnimatableValue(7.0)));
-}
-
-TEST(AnimationKeyframeAnimationEffectTest, ZeroKeyframes)
-{
- RefPtr<KeyframeAnimationEffect> effect = KeyframeAnimationEffect::create(KeyframeAnimationEffect::KeyframeVector());
- EXPECT_TRUE(effect->sample(0, 0.5)->isEmpty());
-}
-
-TEST(AnimationKeyframeAnimationEffectTest, SingleKeyframeAtOffsetZero)
-{
- KeyframeAnimationEffect::KeyframeVector keyframes(1);
- keyframes[0] = Keyframe::create();
- keyframes[0]->setOffset(0.0);
- keyframes[0]->setPropertyValue(CSSPropertyLeft, unknownAnimatableValue(3.0));
-
- RefPtr<KeyframeAnimationEffect> effect = KeyframeAnimationEffect::create(keyframes);
- expectDoubleValue(3.0, effect->sample(0, 0.6)->at(0).second->compositeOnto(unknownAnimatableValue(7.0)));
-}
-
-TEST(AnimationKeyframeAnimationEffectTest, SingleKeyframeAtOffsetOne)
-{
- KeyframeAnimationEffect::KeyframeVector keyframes(1);
- keyframes[0] = Keyframe::create();
- keyframes[0]->setOffset(1.0);
- keyframes[0]->setPropertyValue(CSSPropertyLeft, pixelAnimatableValue(5.0));
-
- RefPtr<KeyframeAnimationEffect> effect = KeyframeAnimationEffect::create(keyframes);
- expectDoubleValue(7.0 * 0.4 + 5.0 * 0.6, effect->sample(0, 0.6)->at(0).second->compositeOnto(pixelAnimatableValue(7.0)));
-}
-
-TEST(AnimationKeyframeAnimationEffectTest, MoreThanTwoKeyframes)
-{
- KeyframeAnimationEffect::KeyframeVector keyframes(3);
- keyframes[0] = Keyframe::create();
- keyframes[0]->setOffset(0.0);
- keyframes[0]->setPropertyValue(CSSPropertyLeft, unknownAnimatableValue(3.0));
- keyframes[1] = Keyframe::create();
- keyframes[1]->setOffset(0.5);
- keyframes[1]->setPropertyValue(CSSPropertyLeft, unknownAnimatableValue(4.0));
- keyframes[2] = Keyframe::create();
- keyframes[2]->setOffset(1.0);
- keyframes[2]->setPropertyValue(CSSPropertyLeft, unknownAnimatableValue(5.0));
-
- RefPtr<KeyframeAnimationEffect> effect = KeyframeAnimationEffect::create(keyframes);
- expectDoubleValue(4.0, effect->sample(0, 0.3)->at(0).second->compositeOnto(unknownAnimatableValue(7.0)));
- expectDoubleValue(5.0, effect->sample(0, 0.8)->at(0).second->compositeOnto(unknownAnimatableValue(7.0)));
-}
-
-TEST(AnimationKeyframeAnimationEffectTest, EndKeyframeOffsetsUnspecified)
-{
- KeyframeAnimationEffect::KeyframeVector keyframes(3);
- keyframes[0] = Keyframe::create();
- keyframes[0]->setPropertyValue(CSSPropertyLeft, unknownAnimatableValue(3.0));
- keyframes[1] = Keyframe::create();
- keyframes[1]->setOffset(0.5);
- keyframes[1]->setPropertyValue(CSSPropertyLeft, unknownAnimatableValue(4.0));
- keyframes[2] = Keyframe::create();
- keyframes[2]->setPropertyValue(CSSPropertyLeft, unknownAnimatableValue(5.0));
-
- RefPtr<KeyframeAnimationEffect> effect = KeyframeAnimationEffect::create(keyframes);
- expectDoubleValue(3.0, effect->sample(0, 0.1)->at(0).second->compositeOnto(unknownAnimatableValue(7.0)));
- expectDoubleValue(4.0, effect->sample(0, 0.6)->at(0).second->compositeOnto(unknownAnimatableValue(7.0)));
- expectDoubleValue(5.0, effect->sample(0, 0.9)->at(0).second->compositeOnto(unknownAnimatableValue(7.0)));
-}
-
-TEST(AnimationKeyframeAnimationEffectTest, SampleOnKeyframe)
-{
- KeyframeAnimationEffect::KeyframeVector keyframes(3);
- keyframes[0] = Keyframe::create();
- keyframes[0]->setOffset(0.0);
- keyframes[0]->setPropertyValue(CSSPropertyLeft, unknownAnimatableValue(3.0));
- keyframes[1] = Keyframe::create();
- keyframes[1]->setOffset(0.5);
- keyframes[1]->setPropertyValue(CSSPropertyLeft, unknownAnimatableValue(4.0));
- keyframes[2] = Keyframe::create();
- keyframes[2]->setOffset(1.0);
- keyframes[2]->setPropertyValue(CSSPropertyLeft, unknownAnimatableValue(5.0));
-
- RefPtr<KeyframeAnimationEffect> effect = KeyframeAnimationEffect::create(keyframes);
- expectDoubleValue(3.0, effect->sample(0, 0.0)->at(0).second->compositeOnto(unknownAnimatableValue(7.0)));
- expectDoubleValue(4.0, effect->sample(0, 0.5)->at(0).second->compositeOnto(unknownAnimatableValue(7.0)));
- expectDoubleValue(5.0, effect->sample(0, 1.0)->at(0).second->compositeOnto(unknownAnimatableValue(7.0)));
-}
-
-// Note that this tests an implementation detail, not behaviour defined by the spec.
-TEST(AnimationKeyframeAnimationEffectTest, SampleReturnsSameAnimatableValueInstance)
-{
- AnimatableValue* threePixelsValue = unknownAnimatableValue(3.0);
- AnimatableValue* fourPixelsValue = unknownAnimatableValue(4.0);
- AnimatableValue* fivePixelsValue = unknownAnimatableValue(5.0);
-
- KeyframeAnimationEffect::KeyframeVector keyframes(3);
- keyframes[0] = Keyframe::create();
- keyframes[0]->setOffset(0.0);
- keyframes[0]->setPropertyValue(CSSPropertyLeft, threePixelsValue);
- keyframes[1] = Keyframe::create();
- keyframes[1]->setOffset(0.5);
- keyframes[1]->setPropertyValue(CSSPropertyLeft, fourPixelsValue);
- keyframes[2] = Keyframe::create();
- keyframes[2]->setOffset(1.0);
- keyframes[2]->setPropertyValue(CSSPropertyLeft, fivePixelsValue);
-
- RefPtr<KeyframeAnimationEffect> effect = KeyframeAnimationEffect::create(keyframes);
- EXPECT_EQ(threePixelsValue, effect->sample(0, 0.0)->at(0).second->compositeOnto(unknownAnimatableValue(7.0)));
- EXPECT_EQ(threePixelsValue, effect->sample(0, 0.1)->at(0).second->compositeOnto(unknownAnimatableValue(7.0)));
- EXPECT_EQ(fourPixelsValue, effect->sample(0, 0.4)->at(0).second->compositeOnto(unknownAnimatableValue(7.0)));
- EXPECT_EQ(fourPixelsValue, effect->sample(0, 0.5)->at(0).second->compositeOnto(unknownAnimatableValue(7.0)));
- EXPECT_EQ(fourPixelsValue, effect->sample(0, 0.6)->at(0).second->compositeOnto(unknownAnimatableValue(7.0)));
- EXPECT_EQ(fivePixelsValue, effect->sample(0, 0.9)->at(0).second->compositeOnto(unknownAnimatableValue(7.0)));
- EXPECT_EQ(fivePixelsValue, effect->sample(0, 1.0)->at(0).second->compositeOnto(unknownAnimatableValue(7.0)));
-}
-
-TEST(AnimationKeyframeAnimationEffectTest, MultipleKeyframesWithSameOffset)
-{
- KeyframeAnimationEffect::KeyframeVector keyframes(7);
- keyframes[0] = Keyframe::create();
- keyframes[0]->setOffset(0.1);
- keyframes[0]->setPropertyValue(CSSPropertyLeft, unknownAnimatableValue(1.0));
- keyframes[1] = Keyframe::create();
- keyframes[1]->setOffset(0.1);
- keyframes[1]->setPropertyValue(CSSPropertyLeft, unknownAnimatableValue(2.0));
- keyframes[2] = Keyframe::create();
- keyframes[2]->setOffset(0.5);
- keyframes[2]->setPropertyValue(CSSPropertyLeft, unknownAnimatableValue(3.0));
- keyframes[3] = Keyframe::create();
- keyframes[3]->setOffset(0.5);
- keyframes[3]->setPropertyValue(CSSPropertyLeft, unknownAnimatableValue(4.0));
- keyframes[4] = Keyframe::create();
- keyframes[4]->setOffset(0.5);
- keyframes[4]->setPropertyValue(CSSPropertyLeft, unknownAnimatableValue(5.0));
- keyframes[5] = Keyframe::create();
- keyframes[5]->setOffset(0.9);
- keyframes[5]->setPropertyValue(CSSPropertyLeft, unknownAnimatableValue(6.0));
- keyframes[6] = Keyframe::create();
- keyframes[6]->setOffset(0.9);
- keyframes[6]->setPropertyValue(CSSPropertyLeft, unknownAnimatableValue(7.0));
-
- RefPtr<KeyframeAnimationEffect> effect = KeyframeAnimationEffect::create(keyframes);
- expectDoubleValue(2.0, effect->sample(0, 0.0)->at(0).second->compositeOnto(unknownAnimatableValue(8.0)));
- expectDoubleValue(2.0, effect->sample(0, 0.2)->at(0).second->compositeOnto(unknownAnimatableValue(8.0)));
- expectDoubleValue(3.0, effect->sample(0, 0.4)->at(0).second->compositeOnto(unknownAnimatableValue(8.0)));
- expectDoubleValue(5.0, effect->sample(0, 0.5)->at(0).second->compositeOnto(unknownAnimatableValue(8.0)));
- expectDoubleValue(5.0, effect->sample(0, 0.6)->at(0).second->compositeOnto(unknownAnimatableValue(8.0)));
- expectDoubleValue(6.0, effect->sample(0, 0.8)->at(0).second->compositeOnto(unknownAnimatableValue(8.0)));
- expectDoubleValue(6.0, effect->sample(0, 1.0)->at(0).second->compositeOnto(unknownAnimatableValue(8.0)));
-}
-
-TEST(AnimationKeyframeAnimationEffectTest, PerKeyframeComposite)
-{
- KeyframeAnimationEffect::KeyframeVector keyframes(2);
- keyframes[0] = Keyframe::create();
- keyframes[0]->setOffset(0.0);
- keyframes[0]->setPropertyValue(CSSPropertyLeft, pixelAnimatableValue(3.0));
- keyframes[1] = Keyframe::create();
- keyframes[1]->setOffset(1.0);
- keyframes[1]->setPropertyValue(CSSPropertyLeft, pixelAnimatableValue(5.0));
- keyframes[1]->setComposite(AnimationEffect::CompositeAdd);
-
- RefPtr<KeyframeAnimationEffect> effect = KeyframeAnimationEffect::create(keyframes);
- expectDoubleValue(3.0 * 0.4 + (7.0 + 5.0) * 0.6, effect->sample(0, 0.6)->at(0).second->compositeOnto(pixelAnimatableValue(7.0)));
-}
-
-TEST(AnimationKeyframeAnimationEffectTest, MultipleProperties)
-{
- KeyframeAnimationEffect::KeyframeVector keyframes(2);
- keyframes[0] = Keyframe::create();
- keyframes[0]->setOffset(0.0);
- keyframes[0]->setPropertyValue(CSSPropertyLeft, unknownAnimatableValue(3.0));
- keyframes[0]->setPropertyValue(CSSPropertyRight, unknownAnimatableValue(4.0));
- keyframes[1] = Keyframe::create();
- keyframes[1]->setOffset(1.0);
- keyframes[1]->setPropertyValue(CSSPropertyLeft, unknownAnimatableValue(5.0));
- keyframes[1]->setPropertyValue(CSSPropertyRight, unknownAnimatableValue(6.0));
-
- RefPtr<KeyframeAnimationEffect> effect = KeyframeAnimationEffect::create(keyframes);
- OwnPtr<AnimationEffect::CompositableValueList> values = effect->sample(0, 0.6);
- ASSERT_EQ(2UL, values->size());
- EXPECT_TRUE(values->at(0).first == CSSPropertyLeft);
- expectDoubleValue(5.0, values->at(0).second->compositeOnto(unknownAnimatableValue(7.0)));
- EXPECT_TRUE(values->at(1).first == CSSPropertyRight);
- expectDoubleValue(6.0, values->at(1).second->compositeOnto(unknownAnimatableValue(7.0)));
-}
-
-TEST(AnimationKeyframeAnimationEffectTest, RecompositeCompositableValue)
-{
- KeyframeAnimationEffect::KeyframeVector keyframes = keyframesAtZeroAndOne(pixelAnimatableValue(3.0), pixelAnimatableValue(5.0));
- keyframes[0]->setComposite(AnimationEffect::CompositeAdd);
- keyframes[1]->setComposite(AnimationEffect::CompositeAdd);
- RefPtr<KeyframeAnimationEffect> effect = KeyframeAnimationEffect::create(keyframes);
- OwnPtr<AnimationEffect::CompositableValueList> values = effect->sample(0, 0.6);
- expectDoubleValue((7.0 + 3.0) * 0.4 + (7.0 + 5.0) * 0.6, values->at(0).second->compositeOnto(pixelAnimatableValue(7.0)));
- expectDoubleValue((9.0 + 3.0) * 0.4 + (9.0 + 5.0) * 0.6, values->at(0).second->compositeOnto(pixelAnimatableValue(9.0)));
-}
-
-TEST(AnimationKeyframeAnimationEffectTest, MultipleIterations)
-{
- KeyframeAnimationEffect::KeyframeVector keyframes = keyframesAtZeroAndOne(pixelAnimatableValue(1.0), pixelAnimatableValue(3.0));
- RefPtr<KeyframeAnimationEffect> effect = KeyframeAnimationEffect::create(keyframes);
- expectDoubleValue(2.0, effect->sample(0, 0.5)->at(0).second->compositeOnto(unknownAnimatableValue(0.0)));
- expectDoubleValue(2.0, effect->sample(1, 0.5)->at(0).second->compositeOnto(unknownAnimatableValue(0.0)));
- expectDoubleValue(2.0, effect->sample(2, 0.5)->at(0).second->compositeOnto(unknownAnimatableValue(0.0)));
-}
-
-TEST(AnimationKeyframeAnimationEffectTest, DependsOnUnderlyingValue)
-{
- KeyframeAnimationEffect::KeyframeVector keyframes(3);
- keyframes[0] = Keyframe::create();
- keyframes[0]->setOffset(0.0);
- keyframes[0]->setPropertyValue(CSSPropertyLeft, pixelAnimatableValue(1.0));
- keyframes[0]->setComposite(AnimationEffect::CompositeAdd);
- keyframes[1] = Keyframe::create();
- keyframes[1]->setOffset(0.5);
- keyframes[1]->setPropertyValue(CSSPropertyLeft, pixelAnimatableValue(1.0));
- keyframes[2] = Keyframe::create();
- keyframes[2]->setOffset(1.0);
- keyframes[2]->setPropertyValue(CSSPropertyLeft, pixelAnimatableValue(1.0));
-
- RefPtr<KeyframeAnimationEffect> effect = KeyframeAnimationEffect::create(keyframes);
- EXPECT_TRUE(effect->sample(0, 0)->at(0).second->dependsOnUnderlyingValue());
- EXPECT_TRUE(effect->sample(0, 0.1)->at(0).second->dependsOnUnderlyingValue());
- EXPECT_TRUE(effect->sample(0, 0.25)->at(0).second->dependsOnUnderlyingValue());
- EXPECT_TRUE(effect->sample(0, 0.4)->at(0).second->dependsOnUnderlyingValue());
- EXPECT_FALSE(effect->sample(0, 0.5)->at(0).second->dependsOnUnderlyingValue());
- EXPECT_FALSE(effect->sample(0, 0.6)->at(0).second->dependsOnUnderlyingValue());
- EXPECT_FALSE(effect->sample(0, 0.75)->at(0).second->dependsOnUnderlyingValue());
- EXPECT_FALSE(effect->sample(0, 0.8)->at(0).second->dependsOnUnderlyingValue());
- EXPECT_FALSE(effect->sample(0, 1)->at(0).second->dependsOnUnderlyingValue());
-}
-
-TEST(AnimationKeyframeAnimationEffectTest, ToKeyframeAnimationEffect)
-{
- KeyframeAnimationEffect::KeyframeVector keyframes(0);
- RefPtr<KeyframeAnimationEffect> effect = KeyframeAnimationEffect::create(keyframes);
-
- AnimationEffect* baseEffect = effect.get();
- EXPECT_TRUE(toKeyframeAnimationEffect(baseEffect));
-}
-
-} // namespace
diff --git a/chromium/third_party/WebKit/Source/core/animation/KeyframeEffectModel.cpp b/chromium/third_party/WebKit/Source/core/animation/KeyframeEffectModel.cpp
new file mode 100644
index 00000000000..c9f2a3fbbe9
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/KeyframeEffectModel.cpp
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "core/animation/KeyframeEffectModel.h"
+
+#include "core/StylePropertyShorthand.h"
+#include "core/animation/AnimationNode.h"
+#include "wtf/text/StringHash.h"
+
+namespace WebCore {
+
+PropertySet KeyframeEffectModelBase::properties() const
+{
+ PropertySet result;
+ if (!m_keyframes.size()) {
+ return result;
+ }
+ result = m_keyframes[0]->properties();
+ for (size_t i = 1; i < m_keyframes.size(); i++) {
+ PropertySet extras = m_keyframes[i]->properties();
+ for (PropertySet::const_iterator it = extras.begin(); it != extras.end(); ++it) {
+ result.add(*it);
+ }
+ }
+ return result;
+}
+
+PassOwnPtrWillBeRawPtr<WillBeHeapVector<RefPtrWillBeMember<Interpolation> > > KeyframeEffectModelBase::sample(int iteration, double fraction, double iterationDuration) const
+{
+ ASSERT(iteration >= 0);
+ ASSERT(!isNull(fraction));
+ ensureKeyframeGroups();
+ ensureInterpolationEffect();
+
+ return m_interpolationEffect->getActiveInterpolations(fraction, iterationDuration);
+}
+
+KeyframeEffectModelBase::KeyframeVector KeyframeEffectModelBase::normalizedKeyframes(const KeyframeVector& keyframes)
+{
+ // keyframes [beginIndex, endIndex) will remain after removing all keyframes if they are not
+ // loosely sorted by offset, and after removing keyframes with positional offset outide [0, 1].
+ size_t beginIndex = 0;
+ size_t endIndex = keyframes.size();
+
+ // Becomes the most recent keyframe with an explicit offset.
+ size_t lastIndex = endIndex;
+ double lastOffset = std::numeric_limits<double>::quiet_NaN();
+
+ for (size_t i = 0; i < keyframes.size(); ++i) {
+ double offset = keyframes[i]->offset();
+ if (!isNull(offset)) {
+ if (lastIndex < i && offset < lastOffset) {
+ // The keyframes are not loosely sorted by offset. Exclude all.
+ endIndex = beginIndex;
+ break;
+ }
+
+ if (offset < 0) {
+ // Remove all keyframes up to and including this keyframe.
+ beginIndex = i + 1;
+ } else if (offset > 1) {
+ // Remove all keyframes from this keyframe onwards. Note we must complete our checking
+ // that the keyframes are loosely sorted by offset, so we can't exit the loop early.
+ endIndex = std::min(i, endIndex);
+ }
+
+ lastIndex = i;
+ lastOffset = offset;
+ }
+ }
+
+ KeyframeVector result;
+ if (beginIndex != endIndex) {
+ result.reserveCapacity(endIndex - beginIndex);
+ for (size_t i = beginIndex; i < endIndex; ++i) {
+ result.append(keyframes[i]->clone());
+ }
+
+ if (isNull(result[result.size() - 1]->offset()))
+ result[result.size() - 1]->setOffset(1);
+
+ if (result.size() > 1 && isNull(result[0]->offset()))
+ result[0]->setOffset(0);
+
+ lastIndex = 0;
+ lastOffset = result[0]->offset();
+ for (size_t i = 1; i < result.size(); ++i) {
+ double offset = result[i]->offset();
+ if (!isNull(offset)) {
+ if (lastIndex + 1 < i) {
+ for (size_t j = 1; j < i - lastIndex; ++j)
+ result[lastIndex + j]->setOffset(lastOffset + (offset - lastOffset) * j / (i - lastIndex));
+ }
+ lastIndex = i;
+ lastOffset = offset;
+ }
+ }
+ }
+ return result;
+}
+
+
+void KeyframeEffectModelBase::ensureKeyframeGroups() const
+{
+ if (m_keyframeGroups)
+ return;
+
+ m_keyframeGroups = adoptPtrWillBeNoop(new KeyframeGroupMap);
+ const KeyframeVector keyframes = normalizedKeyframes(getFrames());
+ for (KeyframeVector::const_iterator keyframeIter = keyframes.begin(); keyframeIter != keyframes.end(); ++keyframeIter) {
+ const Keyframe* keyframe = keyframeIter->get();
+ PropertySet keyframeProperties = keyframe->properties();
+ for (PropertySet::const_iterator propertyIter = keyframeProperties.begin(); propertyIter != keyframeProperties.end(); ++propertyIter) {
+ CSSPropertyID property = *propertyIter;
+ ASSERT_WITH_MESSAGE(!isExpandedShorthand(property), "Web Animations: Encountered shorthand CSS property (%d) in normalized keyframes.", property);
+ KeyframeGroupMap::iterator groupIter = m_keyframeGroups->find(property);
+ PropertySpecificKeyframeGroup* group;
+ if (groupIter == m_keyframeGroups->end())
+ group = m_keyframeGroups->add(property, adoptPtrWillBeNoop(new PropertySpecificKeyframeGroup)).storedValue->value.get();
+ else
+ group = groupIter->value.get();
+
+ group->appendKeyframe(keyframe->createPropertySpecificKeyframe(property));
+ }
+ }
+
+ // Add synthetic keyframes.
+ for (KeyframeGroupMap::iterator iter = m_keyframeGroups->begin(); iter != m_keyframeGroups->end(); ++iter) {
+ iter->value->addSyntheticKeyframeIfRequired(this);
+ iter->value->removeRedundantKeyframes();
+ }
+}
+
+void KeyframeEffectModelBase::ensureInterpolationEffect(Element* element) const
+{
+ if (m_interpolationEffect)
+ return;
+ m_interpolationEffect = InterpolationEffect::create();
+
+ for (KeyframeGroupMap::const_iterator iter = m_keyframeGroups->begin(); iter != m_keyframeGroups->end(); ++iter) {
+ const PropertySpecificKeyframeVector& keyframes = iter->value->keyframes();
+ ASSERT(keyframes[0]->composite() == AnimationEffect::CompositeReplace);
+ for (size_t i = 0; i < keyframes.size() - 1; i++) {
+ ASSERT(keyframes[i + 1]->composite() == AnimationEffect::CompositeReplace);
+ double applyFrom = i ? keyframes[i]->offset() : (-std::numeric_limits<double>::infinity());
+ double applyTo = i == keyframes.size() - 2 ? std::numeric_limits<double>::infinity() : keyframes[i + 1]->offset();
+ if (applyTo == 1)
+ applyTo = std::numeric_limits<double>::infinity();
+
+ m_interpolationEffect->addInterpolation(keyframes[i]->createInterpolation(iter->key, keyframes[i + 1].get(), element),
+ keyframes[i]->easing(), keyframes[i]->offset(), keyframes[i + 1]->offset(), applyFrom, applyTo);
+ }
+ }
+}
+
+bool KeyframeEffectModelBase::isReplaceOnly()
+{
+ ensureKeyframeGroups();
+ for (KeyframeGroupMap::iterator iter = m_keyframeGroups->begin(); iter != m_keyframeGroups->end(); ++iter) {
+ const PropertySpecificKeyframeVector& keyframeVector = iter->value->keyframes();
+ for (size_t i = 0; i < keyframeVector.size(); ++i) {
+ if (keyframeVector[i]->composite() != AnimationEffect::CompositeReplace)
+ return false;
+ }
+ }
+ return true;
+}
+
+void KeyframeEffectModelBase::trace(Visitor* visitor)
+{
+ visitor->trace(m_keyframes);
+ visitor->trace(m_interpolationEffect);
+#if ENABLE_OILPAN
+ visitor->trace(m_keyframeGroups);
+#endif
+ AnimationEffect::trace(visitor);
+}
+
+Keyframe::PropertySpecificKeyframe::PropertySpecificKeyframe(double offset, PassRefPtr<TimingFunction> easing, AnimationEffect::CompositeOperation composite)
+ : m_offset(offset)
+ , m_easing(easing)
+ , m_composite(composite)
+{
+}
+
+void KeyframeEffectModelBase::PropertySpecificKeyframeGroup::appendKeyframe(PassOwnPtrWillBeRawPtr<Keyframe::PropertySpecificKeyframe> keyframe)
+{
+ ASSERT(m_keyframes.isEmpty() || m_keyframes.last()->offset() <= keyframe->offset());
+ m_keyframes.append(keyframe);
+}
+
+void KeyframeEffectModelBase::PropertySpecificKeyframeGroup::removeRedundantKeyframes()
+{
+ // As an optimization, removes keyframes in the following categories, as
+ // they will never be used by sample().
+ // - End keyframes with the same offset as their neighbor
+ // - Interior keyframes with the same offset as both their neighbors
+ // Note that synthetic keyframes must be added before this method is
+ // called.
+ ASSERT(m_keyframes.size() >= 2);
+ for (int i = m_keyframes.size() - 1; i >= 0; --i) {
+ double offset = m_keyframes[i]->offset();
+ bool hasSameOffsetAsPreviousNeighbor = !i || m_keyframes[i - 1]->offset() == offset;
+ bool hasSameOffsetAsNextNeighbor = i == static_cast<int>(m_keyframes.size() - 1) || m_keyframes[i + 1]->offset() == offset;
+ if (hasSameOffsetAsPreviousNeighbor && hasSameOffsetAsNextNeighbor)
+ m_keyframes.remove(i);
+ }
+ ASSERT(m_keyframes.size() >= 2);
+}
+
+void KeyframeEffectModelBase::PropertySpecificKeyframeGroup::addSyntheticKeyframeIfRequired(const KeyframeEffectModelBase* context)
+{
+ ASSERT(!m_keyframes.isEmpty());
+ if (m_keyframes.first()->offset() != 0.0)
+ m_keyframes.insert(0, m_keyframes.first()->neutralKeyframe(0, nullptr));
+ if (m_keyframes.last()->offset() != 1.0)
+ appendKeyframe(m_keyframes.last()->neutralKeyframe(1, nullptr));
+}
+
+void KeyframeEffectModelBase::PropertySpecificKeyframeGroup::trace(Visitor* visitor)
+{
+#if ENABLE(OILPAN)
+ visitor->trace(m_keyframes);
+#endif
+}
+
+} // namespace
diff --git a/chromium/third_party/WebKit/Source/core/animation/KeyframeEffectModel.h b/chromium/third_party/WebKit/Source/core/animation/KeyframeEffectModel.h
new file mode 100644
index 00000000000..34feab36d91
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/KeyframeEffectModel.h
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef KeyframeEffectModel_h
+#define KeyframeEffectModel_h
+
+#include "core/animation/AnimatableValueKeyframe.h"
+#include "core/animation/AnimationEffect.h"
+#include "core/animation/AnimationNode.h"
+#include "core/animation/InterpolationEffect.h"
+#include "core/animation/StringKeyframe.h"
+#include "platform/animation/TimingFunction.h"
+#include "platform/heap/Handle.h"
+#include "wtf/HashMap.h"
+#include "wtf/HashSet.h"
+#include "wtf/PassOwnPtr.h"
+#include "wtf/PassRefPtr.h"
+#include "wtf/RefCounted.h"
+#include "wtf/Vector.h"
+
+namespace WebCore {
+
+class Element;
+class KeyframeEffectModelTest;
+
+class KeyframeEffectModelBase : public AnimationEffect {
+public:
+ // FIXME: Implement accumulation.
+
+ typedef WillBeHeapVector<OwnPtrWillBeMember<Keyframe::PropertySpecificKeyframe> > PropertySpecificKeyframeVector;
+ class PropertySpecificKeyframeGroup : public NoBaseWillBeGarbageCollected<PropertySpecificKeyframeGroup> {
+ public:
+ void appendKeyframe(PassOwnPtrWillBeRawPtr<Keyframe::PropertySpecificKeyframe>);
+ const PropertySpecificKeyframeVector& keyframes() const { return m_keyframes; }
+
+ void trace(Visitor*);
+
+ private:
+ void removeRedundantKeyframes();
+ void addSyntheticKeyframeIfRequired(const KeyframeEffectModelBase* context);
+
+ PropertySpecificKeyframeVector m_keyframes;
+
+ friend class KeyframeEffectModelBase;
+ };
+
+ bool isReplaceOnly();
+
+ PropertySet properties() const;
+
+ typedef WillBeHeapVector<RefPtrWillBeMember<Keyframe> > KeyframeVector;
+ const KeyframeVector& getFrames() const { return m_keyframes; }
+ // FIXME: Implement setFrames()
+
+ const PropertySpecificKeyframeVector& getPropertySpecificKeyframes(CSSPropertyID id) const
+ {
+ ensureKeyframeGroups();
+ return m_keyframeGroups->get(id)->keyframes();
+ }
+
+ // AnimationEffect implementation.
+ virtual PassOwnPtrWillBeRawPtr<WillBeHeapVector<RefPtrWillBeMember<Interpolation> > > sample(int iteration, double fraction, double iterationDuration) const OVERRIDE;
+
+ virtual bool isKeyframeEffectModel() const OVERRIDE { return true; }
+
+ virtual bool isAnimatableValueKeyframeEffectModel() const { return false; }
+ virtual bool isStringKeyframeEffectModel() const { return false; }
+
+ virtual void trace(Visitor*) OVERRIDE;
+
+ // FIXME: This is a hack used to resolve CSSValues to AnimatableValues while we have a valid handle on an element.
+ // This should be removed once StringKeyframes no longer uses InterpolableAnimatableValues.
+ void forceConversionsToAnimatableValues(Element* element)
+ {
+ ensureKeyframeGroups();
+ ensureInterpolationEffect(element);
+ }
+
+protected:
+ static KeyframeVector normalizedKeyframes(const KeyframeVector& keyframes);
+
+ // Lazily computes the groups of property-specific keyframes.
+ void ensureKeyframeGroups() const;
+ void ensureInterpolationEffect(Element* = 0) const;
+
+ KeyframeVector m_keyframes;
+ // The spec describes filtering the normalized keyframes at sampling time
+ // to get the 'property-specific keyframes'. For efficiency, we cache the
+ // property-specific lists.
+ typedef WillBeHeapHashMap<CSSPropertyID, OwnPtrWillBeMember<PropertySpecificKeyframeGroup> > KeyframeGroupMap;
+ mutable OwnPtrWillBeMember<KeyframeGroupMap> m_keyframeGroups;
+ mutable RefPtrWillBeMember<InterpolationEffect> m_interpolationEffect;
+
+ friend class KeyframeEffectModelTest;
+
+ bool affects(CSSPropertyID property)
+ {
+ ensureKeyframeGroups();
+ return m_keyframeGroups->contains(property);
+ }
+};
+
+template <class Keyframe>
+class KeyframeEffectModel FINAL : public KeyframeEffectModelBase {
+public:
+ typedef WillBeHeapVector<RefPtrWillBeMember<Keyframe> > KeyframeVector;
+ static PassRefPtrWillBeRawPtr<KeyframeEffectModel<Keyframe> > create(const KeyframeVector& keyframes) { return adoptRefWillBeNoop(new KeyframeEffectModel(keyframes)); }
+
+private:
+ KeyframeEffectModel(const KeyframeVector& keyframes)
+ {
+ m_keyframes.appendVector(keyframes);
+ }
+
+ virtual bool isAnimatableValueKeyframeEffectModel() const { return false; }
+ virtual bool isStringKeyframeEffectModel() const { return false; }
+
+};
+
+typedef KeyframeEffectModelBase::KeyframeVector KeyframeVector;
+typedef KeyframeEffectModelBase::PropertySpecificKeyframeVector PropertySpecificKeyframeVector;
+
+typedef KeyframeEffectModel<AnimatableValueKeyframe> AnimatableValueKeyframeEffectModel;
+typedef AnimatableValueKeyframeEffectModel::KeyframeVector AnimatableValueKeyframeVector;
+typedef AnimatableValueKeyframeEffectModel::PropertySpecificKeyframeVector AnimatableValuePropertySpecificKeyframeVector;
+
+typedef KeyframeEffectModel<StringKeyframe> StringKeyframeEffectModel;
+typedef StringKeyframeEffectModel::KeyframeVector StringKeyframeVector;
+typedef StringKeyframeEffectModel::PropertySpecificKeyframeVector StringPropertySpecificKeyframeVector;
+
+DEFINE_TYPE_CASTS(KeyframeEffectModelBase, AnimationEffect, value, value->isKeyframeEffectModel(), value.isKeyframeEffectModel());
+DEFINE_TYPE_CASTS(AnimatableValueKeyframeEffectModel, KeyframeEffectModelBase, value, value->isAnimatableValueKeyframeEffectModel(), value.isAnimatableValueKeyframeEffectModel());
+
+inline const AnimatableValueKeyframeEffectModel* toAnimatableValueKeyframeEffectModel(const AnimationEffect* base)
+{
+ return toAnimatableValueKeyframeEffectModel(toKeyframeEffectModelBase(base));
+}
+
+inline AnimatableValueKeyframeEffectModel* toAnimatableValueKeyframeEffectModel(AnimationEffect* base)
+{
+ return toAnimatableValueKeyframeEffectModel(toKeyframeEffectModelBase(base));
+}
+
+template <>
+inline bool KeyframeEffectModel<AnimatableValueKeyframe>::isAnimatableValueKeyframeEffectModel() const { return true; }
+
+template <>
+inline bool KeyframeEffectModel<StringKeyframe>::isStringKeyframeEffectModel() const { return true; }
+
+} // namespace WebCore
+
+#endif // KeyframeEffectModel_h
diff --git a/chromium/third_party/WebKit/Source/core/animation/KeyframeEffectModelTest.cpp b/chromium/third_party/WebKit/Source/core/animation/KeyframeEffectModelTest.cpp
new file mode 100644
index 00000000000..7287f9ac16f
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/KeyframeEffectModelTest.cpp
@@ -0,0 +1,564 @@
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "core/animation/KeyframeEffectModel.h"
+
+#include "core/animation/AnimatableLength.h"
+#include "core/animation/AnimatableUnknown.h"
+#include "core/animation/interpolation/LegacyStyleInterpolation.h"
+#include "core/css/CSSPrimitiveValue.h"
+#include "core/css/parser/BisonCSSParser.h"
+#include "core/css/resolver/CSSToStyleMap.h"
+#include <gtest/gtest.h>
+
+using namespace WebCore;
+
+namespace {
+
+const double duration = 1.0;
+
+PassRefPtrWillBeRawPtr<AnimatableValue> unknownAnimatableValue(double n)
+{
+ return AnimatableUnknown::create(CSSPrimitiveValue::create(n, CSSPrimitiveValue::CSS_UNKNOWN).get());
+}
+
+PassRefPtrWillBeRawPtr<AnimatableValue> pixelAnimatableValue(double n)
+{
+ return AnimatableLength::create(Length(n, Fixed), 1);
+}
+
+AnimatableValueKeyframeVector keyframesAtZeroAndOne(PassRefPtrWillBeRawPtr<AnimatableValue> zeroValue, PassRefPtrWillBeRawPtr<AnimatableValue> oneValue)
+{
+ AnimatableValueKeyframeVector keyframes(2);
+ keyframes[0] = AnimatableValueKeyframe::create();
+ keyframes[0]->setOffset(0.0);
+ keyframes[0]->setPropertyValue(CSSPropertyLeft, zeroValue.get());
+ keyframes[1] = AnimatableValueKeyframe::create();
+ keyframes[1]->setOffset(1.0);
+ keyframes[1]->setPropertyValue(CSSPropertyLeft, oneValue.get());
+ return keyframes;
+}
+
+void expectProperty(CSSPropertyID property, PassRefPtrWillBeRawPtr<Interpolation> interpolationValue)
+{
+ LegacyStyleInterpolation* interpolation = toLegacyStyleInterpolation(interpolationValue.get());
+ ASSERT_EQ(property, interpolation->id());
+}
+
+void expectDoubleValue(double expectedValue, PassRefPtrWillBeRawPtr<Interpolation> interpolationValue)
+{
+ LegacyStyleInterpolation* interpolation = toLegacyStyleInterpolation(interpolationValue.get());
+ RefPtrWillBeRawPtr<AnimatableValue> value = interpolation->currentValue();
+
+ ASSERT_TRUE(value->isLength() || value->isUnknown());
+
+ double actualValue;
+ if (value->isLength())
+ actualValue = toAnimatableLength(value.get())->length(1, ValueRangeAll).value();
+ else
+ actualValue = toCSSPrimitiveValue(toAnimatableUnknown(value.get())->toCSSValue().get())->getDoubleValue();
+
+ EXPECT_FLOAT_EQ(static_cast<float>(expectedValue), actualValue);
+}
+
+Interpolation* findValue(WillBeHeapVector<RefPtrWillBeMember<Interpolation> >& values, CSSPropertyID id)
+{
+ for (size_t i = 0; i < values.size(); ++i) {
+ LegacyStyleInterpolation* value = toLegacyStyleInterpolation(values.at(i).get());
+ if (value->id() == id)
+ return value;
+ }
+ return 0;
+}
+
+
+TEST(AnimationKeyframeEffectModel, BasicOperation)
+{
+ AnimatableValueKeyframeVector keyframes = keyframesAtZeroAndOne(unknownAnimatableValue(3.0), unknownAnimatableValue(5.0));
+ RefPtrWillBeRawPtr<AnimatableValueKeyframeEffectModel> effect = AnimatableValueKeyframeEffectModel::create(keyframes);
+ OwnPtrWillBeRawPtr<WillBeHeapVector<RefPtrWillBeMember<Interpolation> > > values = effect->sample(0, 0.6, duration);
+ ASSERT_EQ(1UL, values->size());
+ expectProperty(CSSPropertyLeft, values->at(0));
+ expectDoubleValue(5.0, values->at(0));
+}
+
+TEST(AnimationKeyframeEffectModel, CompositeReplaceNonInterpolable)
+{
+ AnimatableValueKeyframeVector keyframes = keyframesAtZeroAndOne(unknownAnimatableValue(3.0), unknownAnimatableValue(5.0));
+ keyframes[0]->setComposite(AnimationEffect::CompositeReplace);
+ keyframes[1]->setComposite(AnimationEffect::CompositeReplace);
+ RefPtrWillBeRawPtr<AnimatableValueKeyframeEffectModel> effect = AnimatableValueKeyframeEffectModel::create(keyframes);
+ expectDoubleValue(5.0, effect->sample(0, 0.6, duration)->at(0));
+}
+
+TEST(AnimationKeyframeEffectModel, CompositeReplace)
+{
+ AnimatableValueKeyframeVector keyframes = keyframesAtZeroAndOne(pixelAnimatableValue(3.0), pixelAnimatableValue(5.0));
+ keyframes[0]->setComposite(AnimationEffect::CompositeReplace);
+ keyframes[1]->setComposite(AnimationEffect::CompositeReplace);
+ RefPtrWillBeRawPtr<AnimatableValueKeyframeEffectModel> effect = AnimatableValueKeyframeEffectModel::create(keyframes);
+ expectDoubleValue(3.0 * 0.4 + 5.0 * 0.6, effect->sample(0, 0.6, duration)->at(0));
+}
+
+// FIXME: Re-enable this test once compositing of CompositeAdd is supported.
+TEST(AnimationKeyframeEffectModel, DISABLED_CompositeAdd)
+{
+ AnimatableValueKeyframeVector keyframes = keyframesAtZeroAndOne(pixelAnimatableValue(3.0), pixelAnimatableValue(5.0));
+ keyframes[0]->setComposite(AnimationEffect::CompositeAdd);
+ keyframes[1]->setComposite(AnimationEffect::CompositeAdd);
+ RefPtrWillBeRawPtr<AnimatableValueKeyframeEffectModel> effect = AnimatableValueKeyframeEffectModel::create(keyframes);
+ expectDoubleValue((7.0 + 3.0) * 0.4 + (7.0 + 5.0) * 0.6, effect->sample(0, 0.6, duration)->at(0));
+}
+
+TEST(AnimationKeyframeEffectModel, CompositeEaseIn)
+{
+ AnimatableValueKeyframeVector keyframes = keyframesAtZeroAndOne(pixelAnimatableValue(3.0), pixelAnimatableValue(5.0));
+ RefPtrWillBeRawPtr<CSSValue> timingFunction = BisonCSSParser::parseAnimationTimingFunctionValue("ease-in");
+ keyframes[0]->setComposite(AnimationEffect::CompositeReplace);
+ keyframes[0]->setEasing(CSSToStyleMap::mapAnimationTimingFunction(timingFunction.get(), true));
+ keyframes[1]->setComposite(AnimationEffect::CompositeReplace);
+ RefPtrWillBeRawPtr<AnimatableValueKeyframeEffectModel> effect = AnimatableValueKeyframeEffectModel::create(keyframes);
+ expectDoubleValue(3.8579516, effect->sample(0, 0.6, duration)->at(0));
+ expectDoubleValue(3.8582394, effect->sample(0, 0.6, duration * 100)->at(0));
+}
+
+TEST(AnimationKeyframeEffectModel, CompositeCubicBezier)
+{
+ AnimatableValueKeyframeVector keyframes = keyframesAtZeroAndOne(pixelAnimatableValue(3.0), pixelAnimatableValue(5.0));
+ RefPtrWillBeRawPtr<CSSValue> timingFunction = BisonCSSParser::parseAnimationTimingFunctionValue("cubic-bezier(0.42, 0, 0.58, 1)");
+ keyframes[0]->setComposite(AnimationEffect::CompositeReplace);
+ keyframes[0]->setEasing(CSSToStyleMap::mapAnimationTimingFunction(timingFunction.get(), true));
+ keyframes[1]->setComposite(AnimationEffect::CompositeReplace);
+ RefPtrWillBeRawPtr<AnimatableValueKeyframeEffectModel> effect = AnimatableValueKeyframeEffectModel::create(keyframes);
+ expectDoubleValue(4.3363357, effect->sample(0, 0.6, duration)->at(0));
+ expectDoubleValue(4.3362322, effect->sample(0, 0.6, duration * 1000)->at(0));
+}
+
+TEST(AnimationKeyframeEffectModel, ExtrapolateReplaceNonInterpolable)
+{
+ AnimatableValueKeyframeVector keyframes = keyframesAtZeroAndOne(unknownAnimatableValue(3.0), unknownAnimatableValue(5.0));
+ keyframes[0]->setComposite(AnimationEffect::CompositeReplace);
+ keyframes[1]->setComposite(AnimationEffect::CompositeReplace);
+ RefPtrWillBeRawPtr<AnimatableValueKeyframeEffectModel> effect = AnimatableValueKeyframeEffectModel::create(keyframes);
+ expectDoubleValue(5.0, effect->sample(0, 1.6, duration)->at(0));
+}
+
+TEST(AnimationKeyframeEffectModel, ExtrapolateReplace)
+{
+ AnimatableValueKeyframeVector keyframes = keyframesAtZeroAndOne(pixelAnimatableValue(3.0), pixelAnimatableValue(5.0));
+ RefPtrWillBeRawPtr<AnimatableValueKeyframeEffectModel> effect = AnimatableValueKeyframeEffectModel::create(keyframes);
+ keyframes[0]->setComposite(AnimationEffect::CompositeReplace);
+ keyframes[1]->setComposite(AnimationEffect::CompositeReplace);
+ expectDoubleValue(3.0 * -0.6 + 5.0 * 1.6, effect->sample(0, 1.6, duration)->at(0));
+}
+
+// FIXME: Re-enable this test once compositing of CompositeAdd is supported.
+TEST(AnimationKeyframeEffectModel, DISABLED_ExtrapolateAdd)
+{
+ AnimatableValueKeyframeVector keyframes = keyframesAtZeroAndOne(pixelAnimatableValue(3.0), pixelAnimatableValue(5.0));
+ keyframes[0]->setComposite(AnimationEffect::CompositeAdd);
+ keyframes[1]->setComposite(AnimationEffect::CompositeAdd);
+ RefPtrWillBeRawPtr<AnimatableValueKeyframeEffectModel> effect = AnimatableValueKeyframeEffectModel::create(keyframes);
+ expectDoubleValue((7.0 + 3.0) * -0.6 + (7.0 + 5.0) * 1.6, effect->sample(0, 1.6, duration)->at(0));
+}
+
+TEST(AnimationKeyframeEffectModel, ZeroKeyframes)
+{
+ RefPtrWillBeRawPtr<AnimatableValueKeyframeEffectModel> effect = AnimatableValueKeyframeEffectModel::create(AnimatableValueKeyframeVector());
+ EXPECT_TRUE(effect->sample(0, 0.5, duration)->isEmpty());
+}
+
+// FIXME: Re-enable this test once compositing of CompositeAdd is supported.
+TEST(AnimationKeyframeEffectModel, DISABLED_SingleKeyframeAtOffsetZero)
+{
+ AnimatableValueKeyframeVector keyframes(1);
+ keyframes[0] = AnimatableValueKeyframe::create();
+ keyframes[0]->setOffset(0.0);
+ keyframes[0]->setPropertyValue(CSSPropertyLeft, unknownAnimatableValue(3.0).get());
+
+ RefPtrWillBeRawPtr<AnimatableValueKeyframeEffectModel> effect = AnimatableValueKeyframeEffectModel::create(keyframes);
+ expectDoubleValue(3.0, effect->sample(0, 0.6, duration)->at(0));
+}
+
+// FIXME: Re-enable this test once compositing of CompositeAdd is supported.
+TEST(AnimationKeyframeEffectModel, DISABLED_SingleKeyframeAtOffsetOne)
+{
+ AnimatableValueKeyframeVector keyframes(1);
+ keyframes[0] = AnimatableValueKeyframe::create();
+ keyframes[0]->setOffset(1.0);
+ keyframes[0]->setPropertyValue(CSSPropertyLeft, pixelAnimatableValue(5.0).get());
+
+ RefPtrWillBeRawPtr<AnimatableValueKeyframeEffectModel> effect = AnimatableValueKeyframeEffectModel::create(keyframes);
+ expectDoubleValue(7.0 * 0.4 + 5.0 * 0.6, effect->sample(0, 0.6, duration)->at(0));
+}
+
+TEST(AnimationKeyframeEffectModel, MoreThanTwoKeyframes)
+{
+ AnimatableValueKeyframeVector keyframes(3);
+ keyframes[0] = AnimatableValueKeyframe::create();
+ keyframes[0]->setOffset(0.0);
+ keyframes[0]->setPropertyValue(CSSPropertyLeft, unknownAnimatableValue(3.0).get());
+ keyframes[1] = AnimatableValueKeyframe::create();
+ keyframes[1]->setOffset(0.5);
+ keyframes[1]->setPropertyValue(CSSPropertyLeft, unknownAnimatableValue(4.0).get());
+ keyframes[2] = AnimatableValueKeyframe::create();
+ keyframes[2]->setOffset(1.0);
+ keyframes[2]->setPropertyValue(CSSPropertyLeft, unknownAnimatableValue(5.0).get());
+
+ RefPtrWillBeRawPtr<AnimatableValueKeyframeEffectModel> effect = AnimatableValueKeyframeEffectModel::create(keyframes);
+ expectDoubleValue(4.0, effect->sample(0, 0.3, duration)->at(0));
+ expectDoubleValue(5.0, effect->sample(0, 0.8, duration)->at(0));
+}
+
+TEST(AnimationKeyframeEffectModel, EndKeyframeOffsetsUnspecified)
+{
+ AnimatableValueKeyframeVector keyframes(3);
+ keyframes[0] = AnimatableValueKeyframe::create();
+ keyframes[0]->setPropertyValue(CSSPropertyLeft, unknownAnimatableValue(3.0).get());
+ keyframes[1] = AnimatableValueKeyframe::create();
+ keyframes[1]->setOffset(0.5);
+ keyframes[1]->setPropertyValue(CSSPropertyLeft, unknownAnimatableValue(4.0).get());
+ keyframes[2] = AnimatableValueKeyframe::create();
+ keyframes[2]->setPropertyValue(CSSPropertyLeft, unknownAnimatableValue(5.0).get());
+
+ RefPtrWillBeRawPtr<AnimatableValueKeyframeEffectModel> effect = AnimatableValueKeyframeEffectModel::create(keyframes);
+ expectDoubleValue(3.0, effect->sample(0, 0.1, duration)->at(0));
+ expectDoubleValue(4.0, effect->sample(0, 0.6, duration)->at(0));
+ expectDoubleValue(5.0, effect->sample(0, 0.9, duration)->at(0));
+}
+
+TEST(AnimationKeyframeEffectModel, SampleOnKeyframe)
+{
+ AnimatableValueKeyframeVector keyframes(3);
+ keyframes[0] = AnimatableValueKeyframe::create();
+ keyframes[0]->setOffset(0.0);
+ keyframes[0]->setPropertyValue(CSSPropertyLeft, unknownAnimatableValue(3.0).get());
+ keyframes[1] = AnimatableValueKeyframe::create();
+ keyframes[1]->setOffset(0.5);
+ keyframes[1]->setPropertyValue(CSSPropertyLeft, unknownAnimatableValue(4.0).get());
+ keyframes[2] = AnimatableValueKeyframe::create();
+ keyframes[2]->setOffset(1.0);
+ keyframes[2]->setPropertyValue(CSSPropertyLeft, unknownAnimatableValue(5.0).get());
+
+ RefPtrWillBeRawPtr<AnimatableValueKeyframeEffectModel> effect = AnimatableValueKeyframeEffectModel::create(keyframes);
+ expectDoubleValue(3.0, effect->sample(0, 0.0, duration)->at(0));
+ expectDoubleValue(4.0, effect->sample(0, 0.5, duration)->at(0));
+ expectDoubleValue(5.0, effect->sample(0, 1.0, duration)->at(0));
+}
+
+TEST(AnimationKeyframeEffectModel, MultipleKeyframesWithSameOffset)
+{
+ AnimatableValueKeyframeVector keyframes(9);
+ keyframes[0] = AnimatableValueKeyframe::create();
+ keyframes[0]->setOffset(0.0);
+ keyframes[0]->setPropertyValue(CSSPropertyLeft, unknownAnimatableValue(0.0).get());
+ keyframes[1] = AnimatableValueKeyframe::create();
+ keyframes[1]->setOffset(0.1);
+ keyframes[1]->setPropertyValue(CSSPropertyLeft, unknownAnimatableValue(1.0).get());
+ keyframes[2] = AnimatableValueKeyframe::create();
+ keyframes[2]->setOffset(0.1);
+ keyframes[2]->setPropertyValue(CSSPropertyLeft, unknownAnimatableValue(2.0).get());
+ keyframes[3] = AnimatableValueKeyframe::create();
+ keyframes[3]->setOffset(0.5);
+ keyframes[3]->setPropertyValue(CSSPropertyLeft, unknownAnimatableValue(3.0).get());
+ keyframes[4] = AnimatableValueKeyframe::create();
+ keyframes[4]->setOffset(0.5);
+ keyframes[4]->setPropertyValue(CSSPropertyLeft, unknownAnimatableValue(4.0).get());
+ keyframes[5] = AnimatableValueKeyframe::create();
+ keyframes[5]->setOffset(0.5);
+ keyframes[5]->setPropertyValue(CSSPropertyLeft, unknownAnimatableValue(5.0).get());
+ keyframes[6] = AnimatableValueKeyframe::create();
+ keyframes[6]->setOffset(0.9);
+ keyframes[6]->setPropertyValue(CSSPropertyLeft, unknownAnimatableValue(6.0).get());
+ keyframes[7] = AnimatableValueKeyframe::create();
+ keyframes[7]->setOffset(0.9);
+ keyframes[7]->setPropertyValue(CSSPropertyLeft, unknownAnimatableValue(7.0).get());
+ keyframes[8] = AnimatableValueKeyframe::create();
+ keyframes[8]->setOffset(1.0);
+ keyframes[8]->setPropertyValue(CSSPropertyLeft, unknownAnimatableValue(7.0).get());
+
+ RefPtrWillBeRawPtr<AnimatableValueKeyframeEffectModel> effect = AnimatableValueKeyframeEffectModel::create(keyframes);
+ expectDoubleValue(0.0, effect->sample(0, 0.0, duration)->at(0));
+ expectDoubleValue(2.0, effect->sample(0, 0.2, duration)->at(0));
+ expectDoubleValue(3.0, effect->sample(0, 0.4, duration)->at(0));
+ expectDoubleValue(5.0, effect->sample(0, 0.5, duration)->at(0));
+ expectDoubleValue(5.0, effect->sample(0, 0.6, duration)->at(0));
+ expectDoubleValue(6.0, effect->sample(0, 0.8, duration)->at(0));
+ expectDoubleValue(7.0, effect->sample(0, 1.0, duration)->at(0));
+}
+
+// FIXME: Re-enable this test once compositing of CompositeAdd is supported.
+TEST(AnimationKeyframeEffectModel, DISABLED_PerKeyframeComposite)
+{
+ AnimatableValueKeyframeVector keyframes(2);
+ keyframes[0] = AnimatableValueKeyframe::create();
+ keyframes[0]->setOffset(0.0);
+ keyframes[0]->setPropertyValue(CSSPropertyLeft, pixelAnimatableValue(3.0).get());
+ keyframes[1] = AnimatableValueKeyframe::create();
+ keyframes[1]->setOffset(1.0);
+ keyframes[1]->setPropertyValue(CSSPropertyLeft, pixelAnimatableValue(5.0).get());
+ keyframes[1]->setComposite(AnimationEffect::CompositeAdd);
+
+ RefPtrWillBeRawPtr<AnimatableValueKeyframeEffectModel> effect = AnimatableValueKeyframeEffectModel::create(keyframes);
+ expectDoubleValue(3.0 * 0.4 + (7.0 + 5.0) * 0.6, effect->sample(0, 0.6, duration)->at(0));
+}
+
+TEST(AnimationKeyframeEffectModel, MultipleProperties)
+{
+ AnimatableValueKeyframeVector keyframes(2);
+ keyframes[0] = AnimatableValueKeyframe::create();
+ keyframes[0]->setOffset(0.0);
+ keyframes[0]->setPropertyValue(CSSPropertyLeft, unknownAnimatableValue(3.0).get());
+ keyframes[0]->setPropertyValue(CSSPropertyRight, unknownAnimatableValue(4.0).get());
+ keyframes[1] = AnimatableValueKeyframe::create();
+ keyframes[1]->setOffset(1.0);
+ keyframes[1]->setPropertyValue(CSSPropertyLeft, unknownAnimatableValue(5.0).get());
+ keyframes[1]->setPropertyValue(CSSPropertyRight, unknownAnimatableValue(6.0).get());
+
+ RefPtrWillBeRawPtr<AnimatableValueKeyframeEffectModel> effect = AnimatableValueKeyframeEffectModel::create(keyframes);
+ OwnPtrWillBeRawPtr<WillBeHeapVector<RefPtrWillBeMember<Interpolation> > > values = effect->sample(0, 0.6, duration);
+ EXPECT_EQ(2UL, values->size());
+ Interpolation* leftValue = findValue(*values.get(), CSSPropertyLeft);
+ ASSERT_TRUE(leftValue);
+ expectDoubleValue(5.0, leftValue);
+ Interpolation* rightValue = findValue(*values.get(), CSSPropertyRight);
+ ASSERT_TRUE(rightValue);
+ expectDoubleValue(6.0, rightValue);
+}
+
+// FIXME: Re-enable this test once compositing of CompositeAdd is supported.
+TEST(AnimationKeyframeEffectModel, DISABLED_RecompositeCompositableValue)
+{
+ AnimatableValueKeyframeVector keyframes = keyframesAtZeroAndOne(pixelAnimatableValue(3.0), pixelAnimatableValue(5.0));
+ keyframes[0]->setComposite(AnimationEffect::CompositeAdd);
+ keyframes[1]->setComposite(AnimationEffect::CompositeAdd);
+ RefPtrWillBeRawPtr<AnimatableValueKeyframeEffectModel> effect = AnimatableValueKeyframeEffectModel::create(keyframes);
+ OwnPtrWillBeRawPtr<WillBeHeapVector<RefPtrWillBeMember<Interpolation> > > values = effect->sample(0, 0.6, duration);
+ expectDoubleValue((7.0 + 3.0) * 0.4 + (7.0 + 5.0) * 0.6, values->at(0));
+ expectDoubleValue((9.0 + 3.0) * 0.4 + (9.0 + 5.0) * 0.6, values->at(0));
+}
+
+TEST(AnimationKeyframeEffectModel, MultipleIterations)
+{
+ AnimatableValueKeyframeVector keyframes = keyframesAtZeroAndOne(pixelAnimatableValue(1.0), pixelAnimatableValue(3.0));
+ RefPtrWillBeRawPtr<AnimatableValueKeyframeEffectModel> effect = AnimatableValueKeyframeEffectModel::create(keyframes);
+ expectDoubleValue(2.0, effect->sample(0, 0.5, duration)->at(0));
+ expectDoubleValue(2.0, effect->sample(1, 0.5, duration)->at(0));
+ expectDoubleValue(2.0, effect->sample(2, 0.5, duration)->at(0));
+}
+
+// FIXME: Re-enable this test once compositing of CompositeAdd is supported.
+TEST(AnimationKeyframeEffectModel, DISABLED_DependsOnUnderlyingValue)
+{
+ AnimatableValueKeyframeVector keyframes(3);
+ keyframes[0] = AnimatableValueKeyframe::create();
+ keyframes[0]->setOffset(0.0);
+ keyframes[0]->setPropertyValue(CSSPropertyLeft, pixelAnimatableValue(1.0).get());
+ keyframes[0]->setComposite(AnimationEffect::CompositeAdd);
+ keyframes[1] = AnimatableValueKeyframe::create();
+ keyframes[1]->setOffset(0.5);
+ keyframes[1]->setPropertyValue(CSSPropertyLeft, pixelAnimatableValue(1.0).get());
+ keyframes[2] = AnimatableValueKeyframe::create();
+ keyframes[2]->setOffset(1.0);
+ keyframes[2]->setPropertyValue(CSSPropertyLeft, pixelAnimatableValue(1.0).get());
+
+ RefPtrWillBeRawPtr<AnimatableValueKeyframeEffectModel> effect = AnimatableValueKeyframeEffectModel::create(keyframes);
+ EXPECT_TRUE(effect->sample(0, 0, duration)->at(0));
+ EXPECT_TRUE(effect->sample(0, 0.1, duration)->at(0));
+ EXPECT_TRUE(effect->sample(0, 0.25, duration)->at(0));
+ EXPECT_TRUE(effect->sample(0, 0.4, duration)->at(0));
+ EXPECT_FALSE(effect->sample(0, 0.5, duration)->at(0));
+ EXPECT_FALSE(effect->sample(0, 0.6, duration)->at(0));
+ EXPECT_FALSE(effect->sample(0, 0.75, duration)->at(0));
+ EXPECT_FALSE(effect->sample(0, 0.8, duration)->at(0));
+ EXPECT_FALSE(effect->sample(0, 1, duration)->at(0));
+}
+
+TEST(AnimationKeyframeEffectModel, AddSyntheticKeyframes)
+{
+ AnimatableValueKeyframeVector keyframes(1);
+ keyframes[0] = AnimatableValueKeyframe::create();
+ keyframes[0]->setOffset(0.5);
+ keyframes[0]->setPropertyValue(CSSPropertyLeft, unknownAnimatableValue(4.0).get());
+
+ RefPtrWillBeRawPtr<AnimatableValueKeyframeEffectModel> effect = AnimatableValueKeyframeEffectModel::create(keyframes);
+ const AnimatableValuePropertySpecificKeyframeVector& propertySpecificKeyframes = effect->getPropertySpecificKeyframes(CSSPropertyLeft);
+ EXPECT_EQ(3U, propertySpecificKeyframes.size());
+ EXPECT_DOUBLE_EQ(0.0, propertySpecificKeyframes[0]->offset());
+ EXPECT_DOUBLE_EQ(0.5, propertySpecificKeyframes[1]->offset());
+ EXPECT_DOUBLE_EQ(1.0, propertySpecificKeyframes[2]->offset());
+}
+
+TEST(AnimationKeyframeEffectModel, ToKeyframeEffectModel)
+{
+ AnimatableValueKeyframeVector keyframes(0);
+ RefPtrWillBeRawPtr<AnimatableValueKeyframeEffectModel> effect = AnimatableValueKeyframeEffectModel::create(keyframes);
+
+ AnimationEffect* baseEffect = effect.get();
+ EXPECT_TRUE(toAnimatableValueKeyframeEffectModel(baseEffect));
+}
+
+} // namespace
+
+namespace WebCore {
+
+class KeyframeEffectModelTest : public ::testing::Test {
+public:
+ static KeyframeVector normalizedKeyframes(const KeyframeVector& keyframes)
+ {
+ return KeyframeEffectModelBase::normalizedKeyframes(keyframes);
+ }
+};
+
+TEST_F(KeyframeEffectModelTest, NotLooselySorted)
+{
+ KeyframeVector keyframes(4);
+ keyframes[0] = AnimatableValueKeyframe::create();
+ keyframes[1] = AnimatableValueKeyframe::create();
+ keyframes[1]->setOffset(9);
+ keyframes[2] = AnimatableValueKeyframe::create();
+ keyframes[3] = AnimatableValueKeyframe::create();
+ keyframes[3]->setOffset(1);
+
+ const KeyframeVector result = normalizedKeyframes(keyframes);
+ EXPECT_EQ(0U, result.size());
+}
+
+TEST_F(KeyframeEffectModelTest, LastOne)
+{
+ KeyframeVector keyframes(3);
+ keyframes[0] = AnimatableValueKeyframe::create();
+ keyframes[0]->setOffset(-1);
+ keyframes[1] = AnimatableValueKeyframe::create();
+ keyframes[2] = AnimatableValueKeyframe::create();
+ keyframes[2]->setOffset(2);
+
+ const KeyframeVector result = normalizedKeyframes(keyframes);
+ EXPECT_EQ(1U, result.size());
+ EXPECT_DOUBLE_EQ(1.0, result[0]->offset());
+}
+
+TEST_F(KeyframeEffectModelTest, FirstZero)
+{
+ KeyframeVector keyframes(3);
+ keyframes[0] = AnimatableValueKeyframe::create();
+ keyframes[0]->setOffset(-1);
+ keyframes[1] = AnimatableValueKeyframe::create();
+ keyframes[2] = AnimatableValueKeyframe::create();
+ keyframes[2]->setOffset(0.25);
+
+ const KeyframeVector result = normalizedKeyframes(keyframes);
+ EXPECT_EQ(2U, result.size());
+ EXPECT_DOUBLE_EQ(0.0, result[0]->offset());
+ EXPECT_DOUBLE_EQ(0.25, result[1]->offset());
+}
+
+TEST_F(KeyframeEffectModelTest, EvenlyDistributed1)
+{
+ KeyframeVector keyframes(5);
+ keyframes[0] = AnimatableValueKeyframe::create();
+ keyframes[0]->setOffset(0.125);
+ keyframes[1] = AnimatableValueKeyframe::create();
+ keyframes[2] = AnimatableValueKeyframe::create();
+ keyframes[3] = AnimatableValueKeyframe::create();
+ keyframes[4] = AnimatableValueKeyframe::create();
+ keyframes[4]->setOffset(0.625);
+
+ const KeyframeVector result = normalizedKeyframes(keyframes);
+ EXPECT_EQ(5U, result.size());
+ EXPECT_DOUBLE_EQ(0.125, result[0]->offset());
+ EXPECT_DOUBLE_EQ(0.25, result[1]->offset());
+ EXPECT_DOUBLE_EQ(0.375, result[2]->offset());
+ EXPECT_DOUBLE_EQ(0.5, result[3]->offset());
+ EXPECT_DOUBLE_EQ(0.625, result[4]->offset());
+}
+
+TEST_F(KeyframeEffectModelTest, EvenlyDistributed2)
+{
+ KeyframeVector keyframes(8);
+ keyframes[0] = AnimatableValueKeyframe::create();
+ keyframes[0]->setOffset(-0.1);
+ keyframes[1] = AnimatableValueKeyframe::create();
+ keyframes[2] = AnimatableValueKeyframe::create();
+ keyframes[3] = AnimatableValueKeyframe::create();
+ keyframes[4] = AnimatableValueKeyframe::create();
+ keyframes[4]->setOffset(0.75);
+ keyframes[5] = AnimatableValueKeyframe::create();
+ keyframes[6] = AnimatableValueKeyframe::create();
+ keyframes[7] = AnimatableValueKeyframe::create();
+ keyframes[7]->setOffset(1.1);
+
+ const KeyframeVector result = normalizedKeyframes(keyframes);
+ EXPECT_EQ(6U, result.size());
+ EXPECT_DOUBLE_EQ(0.0, result[0]->offset());
+ EXPECT_DOUBLE_EQ(0.25, result[1]->offset());
+ EXPECT_DOUBLE_EQ(0.5, result[2]->offset());
+ EXPECT_DOUBLE_EQ(0.75, result[3]->offset());
+ EXPECT_DOUBLE_EQ(0.875, result[4]->offset());
+ EXPECT_DOUBLE_EQ(1.0, result[5]->offset());
+}
+
+TEST_F(KeyframeEffectModelTest, EvenlyDistributed3)
+{
+ KeyframeVector keyframes(12);
+ keyframes[0] = AnimatableValueKeyframe::create();
+ keyframes[0]->setOffset(0);
+ keyframes[1] = AnimatableValueKeyframe::create();
+ keyframes[2] = AnimatableValueKeyframe::create();
+ keyframes[3] = AnimatableValueKeyframe::create();
+ keyframes[4] = AnimatableValueKeyframe::create();
+ keyframes[4]->setOffset(0.5);
+ keyframes[5] = AnimatableValueKeyframe::create();
+ keyframes[6] = AnimatableValueKeyframe::create();
+ keyframes[7] = AnimatableValueKeyframe::create();
+ keyframes[7]->setOffset(0.8);
+ keyframes[8] = AnimatableValueKeyframe::create();
+ keyframes[9] = AnimatableValueKeyframe::create();
+ keyframes[10] = AnimatableValueKeyframe::create();
+ keyframes[11] = AnimatableValueKeyframe::create();
+
+ const KeyframeVector result = normalizedKeyframes(keyframes);
+ EXPECT_EQ(12U, result.size());
+ EXPECT_DOUBLE_EQ(0.0, result[0]->offset());
+ EXPECT_DOUBLE_EQ(0.125, result[1]->offset());
+ EXPECT_DOUBLE_EQ(0.25, result[2]->offset());
+ EXPECT_DOUBLE_EQ(0.375, result[3]->offset());
+ EXPECT_DOUBLE_EQ(0.5, result[4]->offset());
+ EXPECT_DOUBLE_EQ(0.6, result[5]->offset());
+ EXPECT_DOUBLE_EQ(0.7, result[6]->offset());
+ EXPECT_DOUBLE_EQ(0.8, result[7]->offset());
+ EXPECT_DOUBLE_EQ(0.85, result[8]->offset());
+ EXPECT_DOUBLE_EQ(0.9, result[9]->offset());
+ EXPECT_DOUBLE_EQ(0.95, result[10]->offset());
+ EXPECT_DOUBLE_EQ(1.0, result[11]->offset());
+}
+
+} // namespace WebCore
diff --git a/chromium/third_party/WebKit/Source/core/animation/Player.cpp b/chromium/third_party/WebKit/Source/core/animation/Player.cpp
deleted file mode 100644
index 2fabdd15e17..00000000000
--- a/chromium/third_party/WebKit/Source/core/animation/Player.cpp
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-
-#include "config.h"
-#include "core/animation/Player.h"
-
-#include "core/animation/Animation.h"
-#include "core/animation/DocumentTimeline.h"
-
-namespace WebCore {
-
-namespace {
-
-double effectiveTime(double time) { return isNull(time) ? 0 : time; }
-
-} // namespace
-
-PassRefPtr<Player> Player::create(DocumentTimeline& timeline, TimedItem* content)
-{
- return adoptRef(new Player(timeline, content));
-}
-
-Player::Player(DocumentTimeline& timeline, TimedItem* content)
- : m_pauseStartTime(nullValue())
- , m_playbackRate(1)
- , m_timeDrift(0)
- , m_startTime(nullValue())
- , m_content(content)
- , m_timeline(timeline)
- , m_isPausedForTesting(false)
-{
- if (m_content)
- m_content->attach(this);
-}
-
-Player::~Player()
-{
- if (m_content)
- m_content->detach();
-}
-
-void Player::setStartTime(double startTime)
-{
- ASSERT(!isNull(startTime));
- ASSERT(!hasStartTime());
- m_startTime = startTime;
- update();
-}
-
-double Player::currentTimeBeforeDrift() const
-{
- if (isNull(m_startTime))
- return 0;
- return (effectiveTime(m_timeline.currentTime()) - startTime()) * m_playbackRate;
-}
-
-bool Player::maybeStartAnimationOnCompositor()
-{
- // FIXME: Support starting compositor animations that have a fixed
- // start time.
- ASSERT(!hasStartTime());
- if (!m_content || !m_content->isAnimation())
- return false;
-
- return toAnimation(m_content.get())->maybeStartAnimationOnCompositor();
-}
-
-bool Player::hasActiveAnimationsOnCompositor()
-{
- if (!m_content || !m_content->isAnimation())
- return false;
- return toAnimation(m_content.get())->hasActiveAnimationsOnCompositor();
-}
-
-void Player::cancelAnimationOnCompositor()
-{
- if (hasActiveAnimationsOnCompositor())
- toAnimation(m_content.get())->cancelAnimationOnCompositor();
-}
-
-double Player::pausedTimeDrift() const
-{
- ASSERT(pausedInternal());
- return currentTimeBeforeDrift() - m_pauseStartTime;
-}
-
-double Player::timeDrift() const
-{
- return pausedInternal() ? pausedTimeDrift() : m_timeDrift;
-}
-
-double Player::currentTime() const
-{
- return currentTimeBeforeDrift() - timeDrift();
-}
-
-bool Player::update(double* timeToEffectChange, bool* didTriggerStyleRecalc)
-{
- if (!m_content) {
- if (timeToEffectChange)
- *timeToEffectChange = std::numeric_limits<double>::infinity();
- if (didTriggerStyleRecalc)
- *didTriggerStyleRecalc = false;
- return false;
- }
-
- double inheritedTime = isNull(m_timeline.currentTime()) ? nullValue() : currentTime();
- bool didTriggerStyleRecalcLocal = m_content->updateInheritedTime(inheritedTime);
-
- if (timeToEffectChange)
- *timeToEffectChange = m_content->timeToEffectChange();
- if (didTriggerStyleRecalc)
- *didTriggerStyleRecalc = didTriggerStyleRecalcLocal;
- return m_content->isCurrent() || m_content->isInEffect();
-}
-
-void Player::cancel()
-{
- if (!m_content)
- return;
-
- ASSERT(m_content->player() == this);
- m_content->detach();
- m_content = 0;
-}
-
-void Player::setCurrentTime(double seekTime)
-{
- if (pausedInternal())
- m_pauseStartTime = seekTime;
- else
- m_timeDrift = currentTimeBeforeDrift() - seekTime;
-
- if (m_isPausedForTesting && hasActiveAnimationsOnCompositor())
- toAnimation(m_content.get())->pauseAnimationForTestingOnCompositor(currentTime());
- update();
-}
-
-void Player::pauseForTesting()
-{
- RELEASE_ASSERT(!paused());
- if (!m_isPausedForTesting && hasActiveAnimationsOnCompositor())
- toAnimation(m_content.get())->pauseAnimationForTestingOnCompositor(currentTime());
- m_isPausedForTesting = true;
- setPausedImpl(true);
-}
-
-void Player::setPaused(bool newValue)
-{
- ASSERT(!m_isPausedForTesting);
- setPausedImpl(newValue);
-}
-
-void Player::setPausedImpl(bool newValue)
-{
- if (pausedInternal() == newValue)
- return;
-
- if (newValue) {
- // FIXME: resume compositor animation rather than pull back to main-thread
- cancelAnimationOnCompositor();
- m_pauseStartTime = currentTime();
- } else {
- m_timeDrift = pausedTimeDrift();
- m_pauseStartTime = nullValue();
- }
-}
-
-void Player::setPlaybackRate(double newRate)
-{
- double previousTime = currentTime();
- m_playbackRate = newRate;
- setCurrentTime(previousTime);
-}
-
-} // namespace
diff --git a/chromium/third_party/WebKit/Source/core/animation/Player.h b/chromium/third_party/WebKit/Source/core/animation/Player.h
deleted file mode 100644
index df80447d51e..00000000000
--- a/chromium/third_party/WebKit/Source/core/animation/Player.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef Player_h
-#define Player_h
-
-#include "core/animation/TimedItem.h"
-#include "wtf/RefPtr.h"
-
-namespace WebCore {
-
-class DocumentTimeline;
-
-class Player FINAL : public RefCounted<Player> {
-
-public:
- ~Player();
- static PassRefPtr<Player> create(DocumentTimeline&, TimedItem*);
-
- // Returns whether this player is still current or in effect.
- // timeToEffectChange returns:
- // infinity - if this player is no longer in effect
- // 0 - if this player requires an update on the next frame
- // n - if this player requires an update after 'n' units of time
- bool update(double* timeToEffectChange = 0, bool* didTriggerStyleRecalc = 0);
- void cancel();
-
- double currentTime() const;
- void setCurrentTime(double);
-
- bool paused() const { return !m_isPausedForTesting && pausedInternal(); }
- void setPaused(bool);
-
- double playbackRate() const { return m_playbackRate; }
- void setPlaybackRate(double);
- double timeDrift() const;
- DocumentTimeline& timeline() { return m_timeline; }
-
- bool hasStartTime() const { return !isNull(m_startTime); }
- double startTime() const { return m_startTime; }
- void setStartTime(double);
-
- TimedItem* source() { return m_content.get(); }
-
- // Pausing via this method is not reflected in the value returned by
- // paused() and must never overlap with pausing via setPaused().
- void pauseForTesting();
-
- bool maybeStartAnimationOnCompositor();
- void cancelAnimationOnCompositor();
- bool hasActiveAnimationsOnCompositor();
-
-private:
- Player(DocumentTimeline&, TimedItem*);
- inline double pausedTimeDrift() const;
- inline double currentTimeBeforeDrift() const;
-
-
- void setPausedImpl(bool);
- // Reflects all pausing, including via pauseForTesting().
- bool pausedInternal() const { return !isNull(m_pauseStartTime); }
-
- double m_pauseStartTime;
- double m_playbackRate;
- double m_timeDrift;
- double m_startTime;
-
- RefPtr<TimedItem> m_content;
- DocumentTimeline& m_timeline;
- bool m_isPausedForTesting;
-};
-
-} // namespace
-
-#endif
diff --git a/chromium/third_party/WebKit/Source/core/animation/PlayerTest.cpp b/chromium/third_party/WebKit/Source/core/animation/PlayerTest.cpp
deleted file mode 100644
index 4ff5badddba..00000000000
--- a/chromium/third_party/WebKit/Source/core/animation/PlayerTest.cpp
+++ /dev/null
@@ -1,364 +0,0 @@
-/*
- * Copyright (c) 2013, Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "core/animation/Player.h"
-
-#include "core/animation/ActiveAnimations.h"
-#include "core/animation/Animation.h"
-#include "core/animation/AnimationClock.h"
-#include "core/animation/DocumentTimeline.h"
-#include "core/dom/Document.h"
-#include "core/dom/QualifiedName.h"
-#include "platform/weborigin/KURL.h"
-#include <gtest/gtest.h>
-
-using namespace WebCore;
-
-namespace {
-
-class AnimationPlayerTest : public ::testing::Test {
-protected:
- virtual void SetUp()
- {
- document = Document::create();
- document->animationClock().resetTimeForTesting();
- timeline = DocumentTimeline::create(document.get());
- player = Player::create(*timeline, 0);
- player->setStartTime(0);
- timeline->setZeroTime(0);
- }
-
- bool updateTimeline(double time, double* timeToEffectChange = 0)
- {
- document->animationClock().updateTime(time);
- // The timeline does not know about our player, so we have to explicitly call update().
- return player->update(timeToEffectChange);
- }
-
- RefPtr<Document> document;
- RefPtr<DocumentTimeline> timeline;
- RefPtr<Player> player;
-};
-
-TEST_F(AnimationPlayerTest, InitialState)
-{
- EXPECT_EQ(0, timeline->currentTime());
- EXPECT_EQ(0, player->currentTime());
- EXPECT_FALSE(player->paused());
- EXPECT_EQ(1, player->playbackRate());
- EXPECT_EQ(0, player->startTime());
- EXPECT_EQ(0, player->timeDrift());
-}
-
-TEST_F(AnimationPlayerTest, PauseUnpause)
-{
- updateTimeline(200);
- player->setPaused(true);
- EXPECT_TRUE(player->paused());
- EXPECT_EQ(200, player->currentTime());
- EXPECT_EQ(0, player->timeDrift());
-
- updateTimeline(400);
- player->setPaused(false);
- EXPECT_FALSE(player->paused());
- EXPECT_EQ(200, player->currentTime());
- EXPECT_EQ(200, player->timeDrift());
-
- updateTimeline(600);
- EXPECT_EQ(400, player->currentTime());
- EXPECT_EQ(200, player->timeDrift());
-}
-
-TEST_F(AnimationPlayerTest, PauseBeforeTimelineStarted)
-{
- player->setPaused(true);
- EXPECT_TRUE(player->paused());
- EXPECT_EQ(0, player->currentTime());
- EXPECT_EQ(0, player->timeDrift());
-
- player->setPaused(false);
- EXPECT_FALSE(player->paused());
- EXPECT_EQ(0, player->currentTime());
- EXPECT_EQ(0, player->timeDrift());
-
- player->setPaused(true);
- updateTimeline(100);
- EXPECT_TRUE(player->paused());
- EXPECT_EQ(0, player->currentTime());
- EXPECT_EQ(100, player->timeDrift());
-
- player->setPaused(false);
- EXPECT_EQ(0, player->currentTime());
- EXPECT_EQ(100, player->timeDrift());
-}
-
-TEST_F(AnimationPlayerTest, PauseBeforeStartTimeSet)
-{
- player = Player::create(*timeline, 0);
- updateTimeline(100);
- EXPECT_EQ(0, player->currentTime());
-
- player->setPaused(true);
- updateTimeline(200);
- EXPECT_EQ(0, player->currentTime());
-
- player->setStartTime(150);
- EXPECT_EQ(0, player->currentTime());
-
- player->setPaused(false);
- EXPECT_EQ(0, player->currentTime());
-
- updateTimeline(300);
- EXPECT_EQ(100, player->currentTime());
-}
-
-TEST_F(AnimationPlayerTest, SetCurrentTime)
-{
- updateTimeline(0);
- player->setCurrentTime(250);
- EXPECT_EQ(250, player->currentTime());
- EXPECT_EQ(-250, player->timeDrift());
-}
-
-TEST_F(AnimationPlayerTest, SetStartTime)
-{
- updateTimeline(0);
- player = Player::create(*timeline, 0);
- EXPECT_FALSE(player->hasStartTime());
- EXPECT_TRUE(isNull(player->startTime()));
- EXPECT_EQ(0, player->currentTime());
-
- updateTimeline(100);
- player->setStartTime(50);
- EXPECT_TRUE(player->hasStartTime());
- EXPECT_EQ(50, player->startTime());
- EXPECT_EQ(50, player->currentTime());
-
- updateTimeline(200);
- EXPECT_EQ(150, player->currentTime());
-}
-
-
-TEST_F(AnimationPlayerTest, SetCurrentTimeBeforeTimelineStarted)
-{
- player->setCurrentTime(250);
- EXPECT_EQ(250, player->currentTime());
- EXPECT_EQ(-250, player->timeDrift());
-
- updateTimeline(0);
- EXPECT_EQ(250, player->currentTime());
-}
-
-TEST_F(AnimationPlayerTest, SetCurrentTimeBeforeStartTimeSet)
-{
- updateTimeline(0);
- player = Player::create(*timeline, 0);
-
- player->setCurrentTime(250);
- EXPECT_EQ(250, player->currentTime());
- EXPECT_EQ(-250, player->timeDrift());
-
- updateTimeline(100);
- player->setStartTime(50);
- EXPECT_EQ(300, player->currentTime());
-}
-
-TEST_F(AnimationPlayerTest, SetPlaybackRate)
-{
- updateTimeline(0);
- player->setPlaybackRate(2);
- EXPECT_EQ(2, player->playbackRate());
- EXPECT_EQ(0, player->currentTime());
- EXPECT_EQ(0, player->timeDrift());
-
- updateTimeline(100);
- EXPECT_EQ(200, player->currentTime());
- EXPECT_EQ(0, player->timeDrift());
-}
-
-TEST_F(AnimationPlayerTest, SetPlaybackRateBeforeTimelineStarted)
-{
- player->setPlaybackRate(2);
- EXPECT_EQ(0, player->currentTime());
- EXPECT_EQ(0, player->timeDrift());
-
- updateTimeline(100);
- EXPECT_EQ(200, player->currentTime());
- EXPECT_EQ(0, player->timeDrift());
-}
-
-TEST_F(AnimationPlayerTest, SetPlaybackRateWhilePaused)
-{
- updateTimeline(100);
- player->setPaused(true);
- player->setPlaybackRate(2);
- EXPECT_EQ(100, player->currentTime());
- EXPECT_EQ(100, player->timeDrift());
-
- updateTimeline(200);
- player->setPaused(false);
- EXPECT_EQ(100, player->currentTime());
- EXPECT_EQ(300, player->timeDrift());
-
- updateTimeline(250);
- EXPECT_EQ(200, player->currentTime());
- EXPECT_EQ(300, player->timeDrift());
-}
-
-TEST_F(AnimationPlayerTest, SetPlaybackRateNaN)
-{
- updateTimeline(0);
- player->setPlaybackRate(nullValue());
- EXPECT_TRUE(isNull(player->playbackRate()));
- EXPECT_TRUE(isNull(player->currentTime()));
- EXPECT_TRUE(isNull(player->timeDrift()));
-
- updateTimeline(100);
- EXPECT_TRUE(isNull(player->currentTime()));
- EXPECT_TRUE(isNull(player->timeDrift()));
-}
-
-TEST_F(AnimationPlayerTest, SetPlaybackRateInfinity)
-{
- updateTimeline(0);
- player->setPlaybackRate(std::numeric_limits<double>::infinity());
- EXPECT_EQ(std::numeric_limits<double>::infinity(), player->playbackRate());
- EXPECT_TRUE(isNull(player->currentTime()));
- EXPECT_TRUE(isNull(player->timeDrift()));
-
- updateTimeline(100);
- EXPECT_TRUE(isNull(player->currentTime()));
- EXPECT_TRUE(isNull(player->timeDrift()));
-}
-
-TEST_F(AnimationPlayerTest, SetPlaybackRateMax)
-{
- updateTimeline(0);
- player->setPlaybackRate(std::numeric_limits<double>::max());
- EXPECT_EQ(std::numeric_limits<double>::max(), player->playbackRate());
- EXPECT_EQ(0, player->currentTime());
- EXPECT_EQ(0, player->timeDrift());
-
- updateTimeline(100);
- EXPECT_EQ(std::numeric_limits<double>::infinity(), player->currentTime());
-}
-
-TEST_F(AnimationPlayerTest, SetCurrentTimeNan)
-{
- updateTimeline(0);
- player->setCurrentTime(nullValue());
- EXPECT_TRUE(isNull(player->currentTime()));
- EXPECT_TRUE(isNull(player->timeDrift()));
-
- updateTimeline(100);
- EXPECT_TRUE(isNull(player->currentTime()));
- EXPECT_TRUE(isNull(player->timeDrift()));
-}
-
-TEST_F(AnimationPlayerTest, SetCurrentTimeInfinity)
-{
- updateTimeline(0);
- player->setCurrentTime(std::numeric_limits<double>::infinity());
- EXPECT_EQ(std::numeric_limits<double>::infinity(), player->currentTime());
- EXPECT_EQ(-std::numeric_limits<double>::infinity(), player->timeDrift());
-
- updateTimeline(100);
- EXPECT_EQ(std::numeric_limits<double>::infinity(), player->currentTime());
- EXPECT_EQ(-std::numeric_limits<double>::infinity(), player->timeDrift());
-}
-
-TEST_F(AnimationPlayerTest, SetCurrentTimeMax)
-{
- updateTimeline(0);
- player->setCurrentTime(std::numeric_limits<double>::max());
- EXPECT_EQ(std::numeric_limits<double>::max(), player->currentTime());
- EXPECT_EQ(-std::numeric_limits<double>::max(), player->timeDrift());
-
- updateTimeline(100);
- EXPECT_EQ(std::numeric_limits<double>::max(), player->currentTime());
- EXPECT_EQ(-std::numeric_limits<double>::max(), player->timeDrift());
-}
-
-TEST_F(AnimationPlayerTest, EmptyPlayersDontUpdateEffects)
-{
- double timeToNextEffect;
- updateTimeline(0, &timeToNextEffect);
- EXPECT_EQ(std::numeric_limits<double>::infinity(), timeToNextEffect);
-
- timeToNextEffect = 0;
- updateTimeline(1234, &timeToNextEffect);
- EXPECT_EQ(std::numeric_limits<double>::infinity(), timeToNextEffect);
-}
-
-TEST_F(AnimationPlayerTest, PlayersReturnTimeToNextEffect)
-{
- Timing timing;
- timing.startDelay = 1;
- timing.iterationDuration = 1;
- timing.hasIterationDuration = true;
- RefPtr<Animation> animation = Animation::create(0, 0, timing);
- player = Player::create(*timeline, animation.get());
- player->setStartTime(0);
-
- double timeToNextEffect;
- updateTimeline(0, &timeToNextEffect);
- EXPECT_EQ(1, timeToNextEffect);
-
- updateTimeline(0.5, &timeToNextEffect);
- EXPECT_EQ(0.5, timeToNextEffect);
-
- updateTimeline(1, &timeToNextEffect);
- EXPECT_EQ(0, timeToNextEffect);
-
- updateTimeline(1.5, &timeToNextEffect);
- EXPECT_EQ(0, timeToNextEffect);
-
- updateTimeline(2, &timeToNextEffect);
- EXPECT_EQ(std::numeric_limits<double>::infinity(), timeToNextEffect);
-
- updateTimeline(3, &timeToNextEffect);
- EXPECT_EQ(std::numeric_limits<double>::infinity(), timeToNextEffect);
-}
-
-TEST_F(AnimationPlayerTest, AttachedPlayers)
-{
- RefPtr<Element> element = document->createElement("foo", ASSERT_NO_EXCEPTION);
-
- Timing timing;
- RefPtr<Animation> animation = Animation::create(element, 0, timing);
- RefPtr<Player> player = Player::create(*timeline, animation.get());
- EXPECT_EQ(1U, element->activeAnimations()->players().find(player.get())->value);
-
- player.release();
- EXPECT_TRUE(element->activeAnimations()->players().isEmpty());
-}
-
-}
diff --git a/chromium/third_party/WebKit/Source/core/animation/SampledEffect.cpp b/chromium/third_party/WebKit/Source/core/animation/SampledEffect.cpp
new file mode 100644
index 00000000000..0c5e1548c71
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/SampledEffect.cpp
@@ -0,0 +1,66 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "config.h"
+#include "core/animation/SampledEffect.h"
+
+#include "core/animation/interpolation/StyleInterpolation.h"
+
+namespace WebCore {
+
+SampledEffect::SampledEffect(Animation* animation, PassOwnPtrWillBeRawPtr<WillBeHeapVector<RefPtrWillBeMember<Interpolation> > > interpolations)
+ : m_animation(animation)
+#if !ENABLE(OILPAN)
+ , m_player(animation->player())
+#endif
+ , m_interpolations(interpolations)
+ , m_playerSortInfo(animation->player()->sortInfo())
+ , m_priority(animation->priority())
+{
+ ASSERT(m_interpolations && !m_interpolations->isEmpty());
+}
+
+bool SampledEffect::canChange() const
+{
+#if ENABLE(OILPAN)
+ return m_animation;
+#else
+ if (!m_animation)
+ return false;
+ // FIXME: This check won't be needed when Animation and AnimationPlayer are moved to Oilpan.
+ return !m_player->canFree();
+#endif
+}
+
+void SampledEffect::clear()
+{
+#if !ENABLE(OILPAN)
+ m_player = nullptr;
+#endif
+ m_animation = nullptr;
+ m_interpolations->clear();
+}
+
+void SampledEffect::removeReplacedInterpolationsIfNeeded(const BitArray<numCSSProperties>& replacedProperties)
+{
+ if (canChange() && m_animation->isCurrent())
+ return;
+
+ size_t dest = 0;
+ for (size_t i = 0; i < m_interpolations->size(); i++) {
+ if (!replacedProperties.get(toStyleInterpolation(m_interpolations->at(i).get())->id()))
+ m_interpolations->at(dest++) = m_interpolations->at(i);
+ }
+ m_interpolations->shrink(dest);
+}
+
+void SampledEffect::trace(Visitor* visitor)
+{
+ visitor->trace(m_animation);
+#if ENABLE(OILPAN)
+ visitor->trace(m_interpolations);
+#endif
+}
+
+} // namespace WebCore
diff --git a/chromium/third_party/WebKit/Source/core/animation/SampledEffect.h b/chromium/third_party/WebKit/Source/core/animation/SampledEffect.h
new file mode 100644
index 00000000000..7b4f14617eb
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/SampledEffect.h
@@ -0,0 +1,51 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SampledEffect_h
+#define SampledEffect_h
+
+#include "core/animation/Animation.h"
+#include "core/animation/AnimationPlayer.h"
+#include "core/animation/interpolation/Interpolation.h"
+#include "wtf/BitArray.h"
+#include "wtf/Vector.h"
+
+namespace WebCore {
+
+class SampledEffect : public NoBaseWillBeGarbageCollected<SampledEffect> {
+public:
+ static PassOwnPtrWillBeRawPtr<SampledEffect> create(Animation* animation, PassOwnPtrWillBeRawPtr<WillBeHeapVector<RefPtrWillBeMember<Interpolation> > > interpolations)
+ {
+ return adoptPtrWillBeNoop(new SampledEffect(animation, interpolations));
+ }
+
+ bool canChange() const;
+ void clear();
+
+ const WillBeHeapVector<RefPtrWillBeMember<Interpolation> >& interpolations() const { return *m_interpolations; }
+ void setInterpolations(PassOwnPtrWillBeRawPtr<WillBeHeapVector<RefPtrWillBeMember<Interpolation> > > interpolations) { m_interpolations = interpolations; }
+
+ Animation* animation() const { return m_animation; }
+ const AnimationPlayer::SortInfo& sortInfo() const { return m_playerSortInfo; }
+ Animation::Priority priority() const { return m_priority; }
+
+ void removeReplacedInterpolationsIfNeeded(const BitArray<numCSSProperties>&);
+
+ void trace(Visitor*);
+
+private:
+ SampledEffect(Animation*, PassOwnPtrWillBeRawPtr<WillBeHeapVector<RefPtrWillBeMember<Interpolation> > >);
+
+ RawPtrWillBeWeakMember<Animation> m_animation;
+#if !ENABLE(OILPAN)
+ RefPtr<AnimationPlayer> m_player;
+#endif
+ OwnPtrWillBeMember<WillBeHeapVector<RefPtrWillBeMember<Interpolation> > > m_interpolations;
+ AnimationPlayer::SortInfo m_playerSortInfo;
+ Animation::Priority m_priority;
+};
+
+} // namespace WebCore
+
+#endif
diff --git a/chromium/third_party/WebKit/Source/core/animation/StringKeyframe.cpp b/chromium/third_party/WebKit/Source/core/animation/StringKeyframe.cpp
new file mode 100644
index 00000000000..fe13572eb56
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/StringKeyframe.cpp
@@ -0,0 +1,152 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "config.h"
+#include "core/animation/StringKeyframe.h"
+
+#include "core/animation/css/CSSAnimations.h"
+#include "core/animation/interpolation/DefaultStyleInterpolation.h"
+#include "core/animation/interpolation/DeferredLegacyStyleInterpolation.h"
+#include "core/animation/interpolation/LegacyStyleInterpolation.h"
+#include "core/animation/interpolation/LengthStyleInterpolation.h"
+#include "core/css/resolver/StyleResolver.h"
+#include "core/rendering/style/RenderStyle.h"
+
+namespace WebCore {
+
+StringKeyframe::StringKeyframe(const StringKeyframe& copyFrom)
+ : Keyframe(copyFrom.m_offset, copyFrom.m_composite, copyFrom.m_easing)
+ , m_propertySet(copyFrom.m_propertySet->mutableCopy())
+{
+}
+
+void StringKeyframe::setPropertyValue(CSSPropertyID property, const String& value, StyleSheetContents* styleSheetContents)
+{
+ ASSERT(property != CSSPropertyInvalid);
+ if (CSSAnimations::isAllowedAnimation(property))
+ m_propertySet->setProperty(property, value, false, styleSheetContents);
+}
+
+PropertySet StringKeyframe::properties() const
+{
+ // This is not used in time-critical code, so we probably don't need to
+ // worry about caching this result.
+ PropertySet properties;
+ for (unsigned i = 0; i < m_propertySet->propertyCount(); ++i)
+ properties.add(m_propertySet->propertyAt(i).id());
+ return properties;
+}
+
+PassRefPtrWillBeRawPtr<Keyframe> StringKeyframe::clone() const
+{
+ return adoptRefWillBeNoop(new StringKeyframe(*this));
+}
+PassOwnPtrWillBeRawPtr<Keyframe::PropertySpecificKeyframe> StringKeyframe::createPropertySpecificKeyframe(CSSPropertyID property) const
+{
+ return adoptPtrWillBeNoop(new PropertySpecificKeyframe(offset(), easing(), propertyValue(property), composite()));
+}
+
+void StringKeyframe::trace(Visitor* visitor)
+{
+ visitor->trace(m_propertySet);
+ Keyframe::trace(visitor);
+}
+
+StringKeyframe::PropertySpecificKeyframe::PropertySpecificKeyframe(double offset, PassRefPtr<TimingFunction> easing, CSSValue* value, AnimationEffect::CompositeOperation op)
+ : Keyframe::PropertySpecificKeyframe(offset, easing, op)
+ , m_value(value)
+{ }
+
+StringKeyframe::PropertySpecificKeyframe::PropertySpecificKeyframe(double offset, PassRefPtr<TimingFunction> easing, CSSValue* value)
+ : Keyframe::PropertySpecificKeyframe(offset, easing, AnimationEffect::CompositeReplace)
+ , m_value(value)
+{
+ ASSERT(!isNull(m_offset));
+}
+
+PassRefPtrWillBeRawPtr<Interpolation> StringKeyframe::PropertySpecificKeyframe::createInterpolation(CSSPropertyID property, Keyframe::PropertySpecificKeyframe* end, Element* element) const
+{
+ CSSValue* fromCSSValue = m_value.get();
+ CSSValue* toCSSValue = toStringPropertySpecificKeyframe(end)->value();
+ ValueRange range = ValueRangeAll;
+
+ if (!CSSAnimations::isAnimatableProperty(property))
+ return DefaultStyleInterpolation::create(fromCSSValue, toCSSValue, property);
+
+ switch (property) {
+ case CSSPropertyBorderBottomWidth:
+ case CSSPropertyBorderLeftWidth:
+ case CSSPropertyBorderRightWidth:
+ case CSSPropertyBorderTopWidth:
+ case CSSPropertyFontSize:
+ case CSSPropertyHeight:
+ case CSSPropertyLineHeight:
+ case CSSPropertyMaxHeight:
+ case CSSPropertyMaxWidth:
+ case CSSPropertyMinHeight:
+ case CSSPropertyMinWidth:
+ case CSSPropertyOutlineWidth:
+ case CSSPropertyPaddingBottom:
+ case CSSPropertyPaddingLeft:
+ case CSSPropertyPaddingRight:
+ case CSSPropertyPaddingTop:
+ case CSSPropertyPerspective:
+ case CSSPropertyShapeMargin:
+ case CSSPropertyWidth:
+ range = ValueRangeNonNegative;
+ // Fall through
+ case CSSPropertyBottom:
+ case CSSPropertyLeft:
+ case CSSPropertyLetterSpacing:
+ case CSSPropertyMarginBottom:
+ case CSSPropertyMarginLeft:
+ case CSSPropertyMarginRight:
+ case CSSPropertyMarginTop:
+ case CSSPropertyOutlineOffset:
+ case CSSPropertyRight:
+ case CSSPropertyTop:
+ case CSSPropertyVerticalAlign:
+ case CSSPropertyWordSpacing:
+ if (LengthStyleInterpolation::canCreateFrom(*fromCSSValue) && LengthStyleInterpolation::canCreateFrom(*toCSSValue))
+ return LengthStyleInterpolation::create(fromCSSValue, toCSSValue, property, range);
+ break;
+ default:
+ break;
+ }
+
+ if (DeferredLegacyStyleInterpolation::interpolationRequiresStyleResolve(*fromCSSValue) || DeferredLegacyStyleInterpolation::interpolationRequiresStyleResolve(*toCSSValue))
+ return DeferredLegacyStyleInterpolation::create(fromCSSValue, toCSSValue, property);
+
+ // FIXME: Remove the use of AnimatableValues, RenderStyles and Elements here.
+ // FIXME: Remove this cache
+ ASSERT(element);
+ if (!m_animatableValueCache)
+ m_animatableValueCache = StyleResolver::createAnimatableValueSnapshot(*element, property, *fromCSSValue);
+
+ RefPtrWillBeRawPtr<AnimatableValue> to = StyleResolver::createAnimatableValueSnapshot(*element, property, *toCSSValue);
+ toStringPropertySpecificKeyframe(end)->m_animatableValueCache = to;
+
+ return LegacyStyleInterpolation::create(m_animatableValueCache.get(), to.release(), property);
+}
+
+PassOwnPtrWillBeRawPtr<Keyframe::PropertySpecificKeyframe> StringKeyframe::PropertySpecificKeyframe::neutralKeyframe(double offset, PassRefPtr<TimingFunction> easing) const
+{
+ return adoptPtrWillBeNoop(new PropertySpecificKeyframe(offset, easing, 0, AnimationEffect::CompositeAdd));
+}
+
+PassOwnPtrWillBeRawPtr<Keyframe::PropertySpecificKeyframe> StringKeyframe::PropertySpecificKeyframe::cloneWithOffset(double offset) const
+{
+ Keyframe::PropertySpecificKeyframe* theClone = new PropertySpecificKeyframe(offset, m_easing, m_value.get());
+ toStringPropertySpecificKeyframe(theClone)->m_animatableValueCache = m_animatableValueCache;
+ return adoptPtrWillBeNoop(theClone);
+}
+
+void StringKeyframe::PropertySpecificKeyframe::trace(Visitor* visitor)
+{
+ visitor->trace(m_value);
+ visitor->trace(m_animatableValueCache);
+ Keyframe::PropertySpecificKeyframe::trace(visitor);
+}
+
+}
diff --git a/chromium/third_party/WebKit/Source/core/animation/StringKeyframe.h b/chromium/third_party/WebKit/Source/core/animation/StringKeyframe.h
new file mode 100644
index 00000000000..c6a753e3a76
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/StringKeyframe.h
@@ -0,0 +1,79 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef StringKeyframe_h
+#define StringKeyframe_h
+
+#include "core/animation/Keyframe.h"
+#include "core/css/StylePropertySet.h"
+
+namespace WebCore {
+
+class StyleSheetContents;
+
+class StringKeyframe : public Keyframe {
+public:
+ static PassRefPtrWillBeRawPtr<StringKeyframe> create()
+ {
+ return adoptRefWillBeNoop(new StringKeyframe);
+ }
+ void setPropertyValue(CSSPropertyID, const String& value, StyleSheetContents*);
+ void clearPropertyValue(CSSPropertyID property) { m_propertySet->removeProperty(property); }
+ CSSValue* propertyValue(CSSPropertyID property) const
+ {
+ int index = m_propertySet->findPropertyIndex(property);
+ RELEASE_ASSERT(index >= 0);
+ return m_propertySet->propertyAt(static_cast<unsigned>(index)).value();
+ }
+ virtual PropertySet properties() const OVERRIDE;
+
+ virtual void trace(Visitor*) OVERRIDE;
+
+ class PropertySpecificKeyframe : public Keyframe::PropertySpecificKeyframe {
+ public:
+ PropertySpecificKeyframe(double offset, PassRefPtr<TimingFunction> easing, CSSValue*, AnimationEffect::CompositeOperation);
+
+ CSSValue* value() const { return m_value.get(); }
+ virtual const PassRefPtrWillBeRawPtr<AnimatableValue> getAnimatableValue() const OVERRIDE FINAL {
+ return m_animatableValueCache.get();
+ }
+
+ virtual PassOwnPtrWillBeRawPtr<Keyframe::PropertySpecificKeyframe> neutralKeyframe(double offset, PassRefPtr<TimingFunction> easing) const OVERRIDE FINAL;
+ virtual PassRefPtrWillBeRawPtr<Interpolation> createInterpolation(CSSPropertyID, WebCore::Keyframe::PropertySpecificKeyframe* end, Element*) const OVERRIDE FINAL;
+
+ virtual void trace(Visitor*) OVERRIDE;
+
+ private:
+ PropertySpecificKeyframe(double offset, PassRefPtr<TimingFunction> easing, CSSValue*);
+
+ virtual PassOwnPtrWillBeRawPtr<Keyframe::PropertySpecificKeyframe> cloneWithOffset(double offset) const;
+ virtual bool isStringPropertySpecificKeyframe() const OVERRIDE { return true; }
+
+ RefPtrWillBeMember<CSSValue> m_value;
+ mutable RefPtrWillBeMember<AnimatableValue> m_animatableValueCache;
+ };
+
+private:
+ StringKeyframe()
+ : m_propertySet(MutableStylePropertySet::create())
+ { }
+
+ StringKeyframe(const StringKeyframe& copyFrom);
+
+ virtual PassRefPtrWillBeRawPtr<Keyframe> clone() const OVERRIDE;
+ virtual PassOwnPtrWillBeRawPtr<Keyframe::PropertySpecificKeyframe> createPropertySpecificKeyframe(CSSPropertyID) const OVERRIDE;
+
+ virtual bool isStringKeyframe() const OVERRIDE { return true; }
+
+ RefPtrWillBeMember<MutableStylePropertySet> m_propertySet;
+};
+
+typedef StringKeyframe::PropertySpecificKeyframe StringPropertySpecificKeyframe;
+
+DEFINE_TYPE_CASTS(StringKeyframe, Keyframe, value, value->isStringKeyframe(), value.isStringKeyframe());
+DEFINE_TYPE_CASTS(StringPropertySpecificKeyframe, Keyframe::PropertySpecificKeyframe, value, value->isStringPropertySpecificKeyframe(), value.isStringPropertySpecificKeyframe());
+
+}
+
+#endif
diff --git a/chromium/third_party/WebKit/Source/core/animation/TimedItemTest.cpp b/chromium/third_party/WebKit/Source/core/animation/TimedItemTest.cpp
deleted file mode 100644
index 6bd34ab67cc..00000000000
--- a/chromium/third_party/WebKit/Source/core/animation/TimedItemTest.cpp
+++ /dev/null
@@ -1,782 +0,0 @@
-/*
- * Copyright (c) 2013, Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "core/animation/TimedItem.h"
-
-#include <gtest/gtest.h>
-
-using namespace WebCore;
-
-namespace {
-
-class TestTimedItemEventDelegate : public TimedItem::EventDelegate {
-public:
- void onEventCondition(const TimedItem* timedItem, bool isFirstSample, TimedItem::Phase previousPhase, double previousIteration) OVERRIDE
- {
- m_eventTriggered = true;
- m_phaseChanged = previousPhase != timedItem->phase();
- m_iterationChanged = previousIteration != timedItem->currentIteration();
-
- }
- void reset()
- {
- m_eventTriggered = false;
- m_phaseChanged = false;
- m_iterationChanged = false;
- }
- bool eventTriggered() { return m_eventTriggered; }
- bool phaseChanged() { return m_phaseChanged; }
- bool iterationChanged() { return m_iterationChanged; }
-
-private:
- bool m_eventTriggered;
- bool m_phaseChanged;
- bool m_iterationChanged;
-};
-
-class TestTimedItem : public TimedItem {
-public:
- static PassRefPtr<TestTimedItem> create(const Timing& specified)
- {
- return adoptRef(new TestTimedItem(specified, new TestTimedItemEventDelegate()));
- }
-
- void updateInheritedTime(double time)
- {
- m_eventDelegate->reset();
- TimedItem::updateInheritedTime(time);
- }
-
- bool updateChildrenAndEffects() const OVERRIDE { return false; }
- void willDetach() { }
- TestTimedItemEventDelegate* eventDelegate() { return m_eventDelegate; }
- double calculateTimeToEffectChange(double localTime, double timeToNextIteration) const OVERRIDE
- {
- m_localTime = localTime;
- m_timeToNextIteration = timeToNextIteration;
- return -1;
- }
-
- double takeLocalTime()
- {
- const double result = m_localTime;
- m_localTime = nullValue();
- return result;
- }
-
- double takeTimeToNextIteration()
- {
- const double result = m_timeToNextIteration;
- m_timeToNextIteration = nullValue();
- return result;
- }
-
-private:
- TestTimedItem(const Timing& specified, TestTimedItemEventDelegate* eventDelegate)
- : TimedItem(specified, adoptPtr(eventDelegate))
- , m_eventDelegate(eventDelegate)
- {
- }
-
- TestTimedItemEventDelegate* m_eventDelegate;
- mutable double m_localTime;
- mutable double m_timeToNextIteration;
-};
-
-TEST(AnimationTimedItemTest, Sanity)
-{
- Timing timing;
- timing.hasIterationDuration = true;
- timing.iterationDuration = 2;
- RefPtr<TestTimedItem> timedItem = TestTimedItem::create(timing);
-
- EXPECT_EQ(0, timedItem->startTime());
-
- timedItem->updateInheritedTime(0);
-
- EXPECT_EQ(TimedItem::PhaseActive, timedItem->phase());
- EXPECT_TRUE(timedItem->isInPlay());
- EXPECT_TRUE(timedItem->isCurrent());
- EXPECT_TRUE(timedItem->isInEffect());
- EXPECT_EQ(0, timedItem->currentIteration());
- EXPECT_EQ(0, timedItem->startTime());
- EXPECT_EQ(2, timedItem->activeDuration());
- EXPECT_EQ(0, timedItem->timeFraction());
-
- timedItem->updateInheritedTime(1);
-
- EXPECT_EQ(TimedItem::PhaseActive, timedItem->phase());
- EXPECT_TRUE(timedItem->isInPlay());
- EXPECT_TRUE(timedItem->isCurrent());
- EXPECT_TRUE(timedItem->isInEffect());
- EXPECT_EQ(0, timedItem->currentIteration());
- EXPECT_EQ(0, timedItem->startTime());
- EXPECT_EQ(2, timedItem->activeDuration());
- EXPECT_EQ(0.5, timedItem->timeFraction());
-
- timedItem->updateInheritedTime(2);
-
- EXPECT_EQ(TimedItem::PhaseAfter, timedItem->phase());
- EXPECT_FALSE(timedItem->isInPlay());
- EXPECT_FALSE(timedItem->isCurrent());
- EXPECT_TRUE(timedItem->isInEffect());
- EXPECT_EQ(0, timedItem->currentIteration());
- EXPECT_EQ(0, timedItem->startTime());
- EXPECT_EQ(2, timedItem->activeDuration());
- EXPECT_EQ(1, timedItem->timeFraction());
-
- timedItem->updateInheritedTime(3);
-
- EXPECT_EQ(TimedItem::PhaseAfter, timedItem->phase());
- EXPECT_FALSE(timedItem->isInPlay());
- EXPECT_FALSE(timedItem->isCurrent());
- EXPECT_TRUE(timedItem->isInEffect());
- EXPECT_EQ(0, timedItem->currentIteration());
- EXPECT_EQ(0, timedItem->startTime());
- EXPECT_EQ(2, timedItem->activeDuration());
- EXPECT_EQ(1, timedItem->timeFraction());
-}
-
-TEST(AnimationTimedItemTest, FillForwards)
-{
- Timing timing;
- timing.hasIterationDuration = true;
- timing.iterationDuration = 1;
- RefPtr<TestTimedItem> timedItem = TestTimedItem::create(timing);
-
- timedItem->updateInheritedTime(-1);
- EXPECT_TRUE(isNull(timedItem->timeFraction()));
-
- timedItem->updateInheritedTime(2);
- EXPECT_EQ(1, timedItem->timeFraction());
-}
-
-TEST(AnimationTimedItemTest, FillBackwards)
-{
- Timing timing;
- timing.hasIterationDuration = true;
- timing.iterationDuration = 1;
- timing.fillMode = Timing::FillModeBackwards;
- RefPtr<TestTimedItem> timedItem = TestTimedItem::create(timing);
-
- timedItem->updateInheritedTime(-1);
- EXPECT_EQ(0, timedItem->timeFraction());
-
- timedItem->updateInheritedTime(2);
- EXPECT_TRUE(isNull(timedItem->timeFraction()));
-}
-
-TEST(AnimationTimedItemTest, FillBoth)
-{
- Timing timing;
- timing.hasIterationDuration = true;
- timing.iterationDuration = 1;
- timing.fillMode = Timing::FillModeBoth;
- RefPtr<TestTimedItem> timedItem = TestTimedItem::create(timing);
-
- timedItem->updateInheritedTime(-1);
- EXPECT_EQ(0, timedItem->timeFraction());
-
- timedItem->updateInheritedTime(2);
- EXPECT_EQ(1, timedItem->timeFraction());
-}
-
-TEST(AnimationTimedItemTest, StartDelay)
-{
- Timing timing;
- timing.hasIterationDuration = true;
- timing.iterationDuration = 1;
- timing.startDelay = 0.5;
- RefPtr<TestTimedItem> timedItem = TestTimedItem::create(timing);
-
- timedItem->updateInheritedTime(0);
- EXPECT_TRUE(isNull(timedItem->timeFraction()));
-
- timedItem->updateInheritedTime(0.5);
- EXPECT_EQ(0, timedItem->timeFraction());
-
- timedItem->updateInheritedTime(1.5);
- EXPECT_EQ(1, timedItem->timeFraction());
-}
-
-TEST(AnimationTimedItemTest, ZeroIteration)
-{
- Timing timing;
- timing.hasIterationDuration = true;
- timing.iterationDuration = 1;
- timing.iterationCount = 0;
- RefPtr<TestTimedItem> timedItem = TestTimedItem::create(timing);
-
- timedItem->updateInheritedTime(-1);
- EXPECT_EQ(0, timedItem->activeDuration());
- EXPECT_TRUE(isNull(timedItem->currentIteration()));
- EXPECT_TRUE(isNull(timedItem->timeFraction()));
-
- timedItem->updateInheritedTime(0);
- EXPECT_EQ(0, timedItem->activeDuration());
- EXPECT_EQ(0, timedItem->currentIteration());
- EXPECT_EQ(0, timedItem->timeFraction());
-}
-
-TEST(AnimationTimedItemTest, InfiniteIteration)
-{
- Timing timing;
- timing.hasIterationDuration = true;
- timing.iterationDuration = 1;
- timing.iterationCount = std::numeric_limits<double>::infinity();
- RefPtr<TestTimedItem> timedItem = TestTimedItem::create(timing);
-
- timedItem->updateInheritedTime(-1);
- EXPECT_TRUE(isNull(timedItem->currentIteration()));
- EXPECT_TRUE(isNull(timedItem->timeFraction()));
-
- EXPECT_EQ(std::numeric_limits<double>::infinity(), timedItem->activeDuration());
-
- timedItem->updateInheritedTime(0);
- EXPECT_EQ(0, timedItem->currentIteration());
- EXPECT_EQ(0, timedItem->timeFraction());
-}
-
-TEST(AnimationTimedItemTest, Iteration)
-{
- Timing timing;
- timing.iterationCount = 2;
- timing.hasIterationDuration = true;
- timing.iterationDuration = 2;
- RefPtr<TestTimedItem> timedItem = TestTimedItem::create(timing);
-
- timedItem->updateInheritedTime(0);
- EXPECT_EQ(0, timedItem->currentIteration());
- EXPECT_EQ(0, timedItem->timeFraction());
-
- timedItem->updateInheritedTime(1);
- EXPECT_EQ(0, timedItem->currentIteration());
- EXPECT_EQ(0.5, timedItem->timeFraction());
-
- timedItem->updateInheritedTime(2);
- EXPECT_EQ(1, timedItem->currentIteration());
- EXPECT_EQ(0, timedItem->timeFraction());
-
- timedItem->updateInheritedTime(2);
- EXPECT_EQ(1, timedItem->currentIteration());
- EXPECT_EQ(0, timedItem->timeFraction());
-
- timedItem->updateInheritedTime(5);
- EXPECT_EQ(1, timedItem->currentIteration());
- EXPECT_EQ(1, timedItem->timeFraction());
-}
-
-TEST(AnimationTimedItemTest, IterationStart)
-{
- Timing timing;
- timing.iterationStart = 1.2;
- timing.iterationCount = 2.2;
- timing.hasIterationDuration = true;
- timing.iterationDuration = 1;
- timing.fillMode = Timing::FillModeBoth;
- RefPtr<TestTimedItem> timedItem = TestTimedItem::create(timing);
-
- timedItem->updateInheritedTime(-1);
- EXPECT_EQ(1, timedItem->currentIteration());
- EXPECT_NEAR(0.2, timedItem->timeFraction(), 0.000000000000001);
-
- timedItem->updateInheritedTime(0);
- EXPECT_EQ(1, timedItem->currentIteration());
- EXPECT_NEAR(0.2, timedItem->timeFraction(), 0.000000000000001);
-
- timedItem->updateInheritedTime(10);
- EXPECT_EQ(3, timedItem->currentIteration());
- EXPECT_NEAR(0.4, timedItem->timeFraction(), 0.000000000000001);
-}
-
-TEST(AnimationTimedItemTest, IterationAlternate)
-{
- Timing timing;
- timing.iterationCount = 10;
- timing.hasIterationDuration = true;
- timing.iterationDuration = 1;
- timing.direction = Timing::PlaybackDirectionAlternate;
- RefPtr<TestTimedItem> timedItem = TestTimedItem::create(timing);
-
- timedItem->updateInheritedTime(0.75);
- EXPECT_EQ(0, timedItem->currentIteration());
- EXPECT_EQ(0.75, timedItem->timeFraction());
-
- timedItem->updateInheritedTime(1.75);
- EXPECT_EQ(1, timedItem->currentIteration());
- EXPECT_EQ(0.25, timedItem->timeFraction());
-
- timedItem->updateInheritedTime(2.75);
- EXPECT_EQ(2, timedItem->currentIteration());
- EXPECT_EQ(0.75, timedItem->timeFraction());
-}
-
-TEST(AnimationTimedItemTest, IterationAlternateReverse)
-{
- Timing timing;
- timing.iterationCount = 10;
- timing.hasIterationDuration = true;
- timing.iterationDuration = 1;
- timing.direction = Timing::PlaybackDirectionAlternateReverse;
- RefPtr<TestTimedItem> timedItem = TestTimedItem::create(timing);
-
- timedItem->updateInheritedTime(0.75);
- EXPECT_EQ(0, timedItem->currentIteration());
- EXPECT_EQ(0.25, timedItem->timeFraction());
-
- timedItem->updateInheritedTime(1.75);
- EXPECT_EQ(1, timedItem->currentIteration());
- EXPECT_EQ(0.75, timedItem->timeFraction());
-
- timedItem->updateInheritedTime(2.75);
- EXPECT_EQ(2, timedItem->currentIteration());
- EXPECT_EQ(0.25, timedItem->timeFraction());
-}
-
-TEST(AnimationTimedItemTest, ZeroDurationSanity)
-{
- Timing timing;
- RefPtr<TestTimedItem> timedItem = TestTimedItem::create(timing);
-
- EXPECT_EQ(0, timedItem->startTime());
-
- timedItem->updateInheritedTime(0);
-
- EXPECT_EQ(TimedItem::PhaseAfter, timedItem->phase());
- EXPECT_FALSE(timedItem->isInPlay());
- EXPECT_FALSE(timedItem->isCurrent());
- EXPECT_TRUE(timedItem->isInEffect());
- EXPECT_EQ(0, timedItem->currentIteration());
- EXPECT_EQ(0, timedItem->startTime());
- EXPECT_EQ(0, timedItem->activeDuration());
- EXPECT_EQ(1, timedItem->timeFraction());
-
- timedItem->updateInheritedTime(1);
-
- EXPECT_EQ(TimedItem::PhaseAfter, timedItem->phase());
- EXPECT_FALSE(timedItem->isInPlay());
- EXPECT_FALSE(timedItem->isCurrent());
- EXPECT_TRUE(timedItem->isInEffect());
- EXPECT_EQ(0, timedItem->currentIteration());
- EXPECT_EQ(0, timedItem->startTime());
- EXPECT_EQ(0, timedItem->activeDuration());
- EXPECT_EQ(1, timedItem->timeFraction());
-}
-
-TEST(AnimationTimedItemTest, ZeroDurationFillForwards)
-{
- Timing timing;
- RefPtr<TestTimedItem> timedItem = TestTimedItem::create(timing);
-
- timedItem->updateInheritedTime(-1);
- EXPECT_TRUE(isNull(timedItem->timeFraction()));
-
- timedItem->updateInheritedTime(0);
- EXPECT_EQ(1, timedItem->timeFraction());
-
- timedItem->updateInheritedTime(1);
- EXPECT_EQ(1, timedItem->timeFraction());
-}
-
-TEST(AnimationTimedItemTest, ZeroDurationFillBackwards)
-{
- Timing timing;
- timing.fillMode = Timing::FillModeBackwards;
- RefPtr<TestTimedItem> timedItem = TestTimedItem::create(timing);
-
- timedItem->updateInheritedTime(-1);
- EXPECT_EQ(0, timedItem->timeFraction());
-
- timedItem->updateInheritedTime(0);
- EXPECT_TRUE(isNull(timedItem->timeFraction()));
-
- timedItem->updateInheritedTime(1);
- EXPECT_TRUE(isNull(timedItem->timeFraction()));
-}
-
-TEST(AnimationTimedItemTest, ZeroDurationFillBoth)
-{
- Timing timing;
- timing.fillMode = Timing::FillModeBoth;
- RefPtr<TestTimedItem> timedItem = TestTimedItem::create(timing);
-
- timedItem->updateInheritedTime(-1);
- EXPECT_EQ(0, timedItem->timeFraction());
-
- timedItem->updateInheritedTime(0);
- EXPECT_EQ(1, timedItem->timeFraction());
-
- timedItem->updateInheritedTime(1);
- EXPECT_EQ(1, timedItem->timeFraction());
-}
-
-TEST(AnimationTimedItemTest, ZeroDurationStartDelay)
-{
- Timing timing;
- timing.startDelay = 0.5;
- RefPtr<TestTimedItem> timedItem = TestTimedItem::create(timing);
-
- timedItem->updateInheritedTime(0);
- EXPECT_TRUE(isNull(timedItem->timeFraction()));
-
- timedItem->updateInheritedTime(0.5);
- EXPECT_EQ(1, timedItem->timeFraction());
-
- timedItem->updateInheritedTime(1.5);
- EXPECT_EQ(1, timedItem->timeFraction());
-}
-
-TEST(AnimationTimedItemTest, ZeroDurationIterationStartAndCount)
-{
- Timing timing;
- timing.iterationStart = 0.1;
- timing.iterationCount = 0.2;
- timing.fillMode = Timing::FillModeBoth;
- timing.startDelay = 0.3;
- RefPtr<TestTimedItem> timedItem = TestTimedItem::create(timing);
-
- timedItem->updateInheritedTime(0);
- EXPECT_EQ(0.1, timedItem->timeFraction());
-
- timedItem->updateInheritedTime(0.3);
- EXPECT_DOUBLE_EQ(0.3, timedItem->timeFraction());
-
- timedItem->updateInheritedTime(1);
- EXPECT_DOUBLE_EQ(0.3, timedItem->timeFraction());
-}
-
-// FIXME: Needs specification work.
-TEST(AnimationTimedItemTest, ZeroDurationInfiniteIteration)
-{
- Timing timing;
- timing.iterationCount = std::numeric_limits<double>::infinity();
- RefPtr<TestTimedItem> timedItem = TestTimedItem::create(timing);
-
- timedItem->updateInheritedTime(-1);
- EXPECT_EQ(0, timedItem->activeDuration());
- EXPECT_TRUE(isNull(timedItem->currentIteration()));
- EXPECT_TRUE(isNull(timedItem->timeFraction()));
-
- timedItem->updateInheritedTime(0);
- EXPECT_EQ(0, timedItem->activeDuration());
- EXPECT_EQ(std::numeric_limits<double>::infinity(), timedItem->currentIteration());
- EXPECT_EQ(1, timedItem->timeFraction());
-}
-
-TEST(AnimationTimedItemTest, ZeroDurationIteration)
-{
- Timing timing;
- timing.iterationCount = 2;
- RefPtr<TestTimedItem> timedItem = TestTimedItem::create(timing);
-
- timedItem->updateInheritedTime(-1);
- EXPECT_TRUE(isNull(timedItem->currentIteration()));
- EXPECT_TRUE(isNull(timedItem->timeFraction()));
-
- timedItem->updateInheritedTime(0);
- EXPECT_EQ(1, timedItem->currentIteration());
- EXPECT_EQ(1, timedItem->timeFraction());
-
- timedItem->updateInheritedTime(1);
- EXPECT_EQ(1, timedItem->currentIteration());
- EXPECT_EQ(1, timedItem->timeFraction());
-}
-
-TEST(AnimationTimedItemTest, ZeroDurationIterationStart)
-{
- Timing timing;
- timing.iterationStart = 1.2;
- timing.iterationCount = 2.2;
- timing.fillMode = Timing::FillModeBoth;
- RefPtr<TestTimedItem> timedItem = TestTimedItem::create(timing);
-
- timedItem->updateInheritedTime(-1);
- EXPECT_EQ(1, timedItem->currentIteration());
- EXPECT_NEAR(0.2, timedItem->timeFraction(), 0.000000000000001);
-
- timedItem->updateInheritedTime(0);
- EXPECT_EQ(3, timedItem->currentIteration());
- EXPECT_NEAR(0.4, timedItem->timeFraction(), 0.000000000000001);
-
- timedItem->updateInheritedTime(10);
- EXPECT_EQ(3, timedItem->currentIteration());
- EXPECT_NEAR(0.4, timedItem->timeFraction(), 0.000000000000001);
-}
-
-TEST(AnimationTimedItemTest, ZeroDurationIterationAlternate)
-{
- Timing timing;
- timing.iterationCount = 2;
- timing.direction = Timing::PlaybackDirectionAlternate;
- RefPtr<TestTimedItem> timedItem = TestTimedItem::create(timing);
-
- timedItem->updateInheritedTime(-1);
- EXPECT_TRUE(isNull(timedItem->currentIteration()));
- EXPECT_TRUE(isNull(timedItem->timeFraction()));
-
- timedItem->updateInheritedTime(0);
- EXPECT_EQ(1, timedItem->currentIteration());
- EXPECT_EQ(0, timedItem->timeFraction());
-
- timedItem->updateInheritedTime(1);
- EXPECT_EQ(1, timedItem->currentIteration());
- EXPECT_EQ(0, timedItem->timeFraction());
-}
-
-TEST(AnimationTimedItemTest, ZeroDurationIterationAlternateReverse)
-{
- Timing timing;
- timing.iterationCount = 2;
- timing.direction = Timing::PlaybackDirectionAlternateReverse;
- RefPtr<TestTimedItem> timedItem = TestTimedItem::create(timing);
-
- timedItem->updateInheritedTime(-1);
- EXPECT_TRUE(isNull(timedItem->currentIteration()));
- EXPECT_TRUE(isNull(timedItem->timeFraction()));
-
- timedItem->updateInheritedTime(0);
- EXPECT_EQ(1, timedItem->currentIteration());
- EXPECT_EQ(1, timedItem->timeFraction());
-
- timedItem->updateInheritedTime(1);
- EXPECT_EQ(1, timedItem->currentIteration());
- EXPECT_EQ(1, timedItem->timeFraction());
-}
-
-TEST(AnimationTimedItemTest, InfiniteDurationSanity)
-{
- Timing timing;
- timing.hasIterationDuration = true;
- timing.iterationDuration = std::numeric_limits<double>::infinity();
- timing.iterationCount = 1;
- RefPtr<TestTimedItem> timedItem = TestTimedItem::create(timing);
-
- EXPECT_EQ(0, timedItem->startTime());
-
- timedItem->updateInheritedTime(0);
-
- EXPECT_EQ(std::numeric_limits<double>::infinity(), timedItem->activeDuration());
- EXPECT_EQ(TimedItem::PhaseActive, timedItem->phase());
- EXPECT_TRUE(timedItem->isInPlay());
- EXPECT_TRUE(timedItem->isCurrent());
- EXPECT_TRUE(timedItem->isInEffect());
- EXPECT_EQ(0, timedItem->currentIteration());
- EXPECT_EQ(0, timedItem->timeFraction());
-
- timedItem->updateInheritedTime(1);
-
- EXPECT_EQ(std::numeric_limits<double>::infinity(), timedItem->activeDuration());
- EXPECT_EQ(TimedItem::PhaseActive, timedItem->phase());
- EXPECT_TRUE(timedItem->isInPlay());
- EXPECT_TRUE(timedItem->isCurrent());
- EXPECT_TRUE(timedItem->isInEffect());
- EXPECT_EQ(0, timedItem->currentIteration());
- EXPECT_EQ(0, timedItem->timeFraction());
-}
-
-// FIXME: Needs specification work.
-TEST(AnimationTimedItemTest, InfiniteDurationZeroIterations)
-{
- Timing timing;
- timing.hasIterationDuration = true;
- timing.iterationDuration = std::numeric_limits<double>::infinity();
- timing.iterationCount = 0;
- RefPtr<TestTimedItem> timedItem = TestTimedItem::create(timing);
-
- EXPECT_EQ(0, timedItem->startTime());
-
- timedItem->updateInheritedTime(0);
-
- EXPECT_EQ(0, timedItem->activeDuration());
- EXPECT_EQ(TimedItem::PhaseAfter, timedItem->phase());
- EXPECT_FALSE(timedItem->isInPlay());
- EXPECT_FALSE(timedItem->isCurrent());
- EXPECT_TRUE(timedItem->isInEffect());
- EXPECT_EQ(0, timedItem->currentIteration());
- EXPECT_EQ(0, timedItem->timeFraction());
-
- timedItem->updateInheritedTime(1);
-
- EXPECT_EQ(TimedItem::PhaseAfter, timedItem->phase());
- EXPECT_EQ(TimedItem::PhaseAfter, timedItem->phase());
- EXPECT_FALSE(timedItem->isInPlay());
- EXPECT_FALSE(timedItem->isCurrent());
- EXPECT_TRUE(timedItem->isInEffect());
- EXPECT_EQ(0, timedItem->currentIteration());
- EXPECT_EQ(0, timedItem->timeFraction());
-}
-
-TEST(AnimationTimedItemTest, InfiniteDurationInfiniteIterations)
-{
- Timing timing;
- timing.hasIterationDuration = true;
- timing.iterationDuration = std::numeric_limits<double>::infinity();
- timing.iterationCount = std::numeric_limits<double>::infinity();
- RefPtr<TestTimedItem> timedItem = TestTimedItem::create(timing);
-
- EXPECT_EQ(0, timedItem->startTime());
-
- timedItem->updateInheritedTime(0);
-
- EXPECT_EQ(std::numeric_limits<double>::infinity(), timedItem->activeDuration());
- EXPECT_EQ(TimedItem::PhaseActive, timedItem->phase());
- EXPECT_TRUE(timedItem->isInPlay());
- EXPECT_TRUE(timedItem->isCurrent());
- EXPECT_TRUE(timedItem->isInEffect());
- EXPECT_EQ(0, timedItem->currentIteration());
- EXPECT_EQ(0, timedItem->timeFraction());
-
- timedItem->updateInheritedTime(1);
-
- EXPECT_EQ(std::numeric_limits<double>::infinity(), timedItem->activeDuration());
- EXPECT_EQ(TimedItem::PhaseActive, timedItem->phase());
- EXPECT_TRUE(timedItem->isInPlay());
- EXPECT_TRUE(timedItem->isCurrent());
- EXPECT_TRUE(timedItem->isInEffect());
- EXPECT_EQ(0, timedItem->currentIteration());
- EXPECT_EQ(0, timedItem->timeFraction());
-}
-
-TEST(AnimationTimedItemTest, InfiniteDurationZeroPlaybackRate)
-{
- Timing timing;
- timing.hasIterationDuration = true;
- timing.iterationDuration = std::numeric_limits<double>::infinity();
- timing.playbackRate = 0;
- RefPtr<TestTimedItem> timedItem = TestTimedItem::create(timing);
-
- EXPECT_EQ(0, timedItem->startTime());
-
- timedItem->updateInheritedTime(0);
-
- EXPECT_EQ(std::numeric_limits<double>::infinity(), timedItem->activeDuration());
- EXPECT_EQ(TimedItem::PhaseActive, timedItem->phase());
- EXPECT_TRUE(timedItem->isInPlay());
- EXPECT_TRUE(timedItem->isCurrent());
- EXPECT_TRUE(timedItem->isInEffect());
- EXPECT_EQ(0, timedItem->currentIteration());
- EXPECT_EQ(0, timedItem->timeFraction());
-
- timedItem->updateInheritedTime(std::numeric_limits<double>::infinity());
-
- EXPECT_EQ(std::numeric_limits<double>::infinity(), timedItem->activeDuration());
- EXPECT_EQ(TimedItem::PhaseAfter, timedItem->phase());
- EXPECT_FALSE(timedItem->isInPlay());
- EXPECT_FALSE(timedItem->isCurrent());
- EXPECT_TRUE(timedItem->isInEffect());
- EXPECT_EQ(0, timedItem->currentIteration());
- EXPECT_EQ(0, timedItem->timeFraction());
-}
-
-TEST(AnimationTimedItemTest, Events)
-{
- Timing timing;
- timing.hasIterationDuration = true;
- timing.iterationDuration = 1;
- timing.iterationCount = 2;
- timing.startDelay = 1;
- RefPtr<TestTimedItem> timedItem = TestTimedItem::create(timing);
-
- // First sample
- timedItem->updateInheritedTime(0.0);
- EXPECT_TRUE(timedItem->eventDelegate()->eventTriggered());
-
- // Before start
- timedItem->updateInheritedTime(0.5);
- EXPECT_FALSE(timedItem->eventDelegate()->eventTriggered());
-
- // First iteration
- timedItem->updateInheritedTime(1.5);
- EXPECT_TRUE(timedItem->eventDelegate()->eventTriggered());
- EXPECT_TRUE(timedItem->eventDelegate()->phaseChanged());
- EXPECT_TRUE(timedItem->eventDelegate()->iterationChanged());
-
- timedItem->updateInheritedTime(1.6);
- EXPECT_FALSE(timedItem->eventDelegate()->eventTriggered());
-
- // Second iteration
- timedItem->updateInheritedTime(2.5);
- EXPECT_TRUE(timedItem->eventDelegate()->eventTriggered());
- EXPECT_FALSE(timedItem->eventDelegate()->phaseChanged());
- EXPECT_TRUE(timedItem->eventDelegate()->iterationChanged());
-
- timedItem->updateInheritedTime(2.6);
- EXPECT_FALSE(timedItem->eventDelegate()->eventTriggered());
-
- // After end
- timedItem->updateInheritedTime(3.5);
- EXPECT_TRUE(timedItem->eventDelegate()->eventTriggered());
- EXPECT_TRUE(timedItem->eventDelegate()->phaseChanged());
- EXPECT_FALSE(timedItem->eventDelegate()->iterationChanged());
-
- timedItem->updateInheritedTime(3.6);
- EXPECT_FALSE(timedItem->eventDelegate()->eventTriggered());
-}
-
-TEST(AnimationTimedItemTest, TimeToEffectChange)
-{
- Timing timing;
- timing.hasIterationDuration = true;
- timing.iterationDuration = 1;
- timing.iterationStart = 0.2;
- timing.iterationCount = 2.5;
- timing.startDelay = 1;
- timing.direction = Timing::PlaybackDirectionAlternate;
- RefPtr<TestTimedItem> timedItem = TestTimedItem::create(timing);
-
- timedItem->updateInheritedTime(0);
- EXPECT_EQ(0, timedItem->takeLocalTime());
- EXPECT_TRUE(std::isinf(timedItem->takeTimeToNextIteration()));
-
- // Normal iteration.
- timedItem->updateInheritedTime(1.75);
- EXPECT_EQ(1.75, timedItem->takeLocalTime());
- EXPECT_NEAR(0.05, timedItem->takeTimeToNextIteration(), 0.000000000000001);
-
- // Reverse iteration.
- timedItem->updateInheritedTime(2.75);
- EXPECT_EQ(2.75, timedItem->takeLocalTime());
- EXPECT_NEAR(0.05, timedItem->takeTimeToNextIteration(), 0.000000000000001);
-
- // Item ends before iteration finishes.
- timedItem->updateInheritedTime(3.4);
- EXPECT_EQ(TimedItem::PhaseActive, timedItem->phase());
- EXPECT_EQ(3.4, timedItem->takeLocalTime());
- EXPECT_TRUE(std::isinf(timedItem->takeTimeToNextIteration()));
-
- // Item has finished.
- timedItem->updateInheritedTime(3.5);
- EXPECT_EQ(TimedItem::PhaseAfter, timedItem->phase());
- EXPECT_EQ(3.5, timedItem->takeLocalTime());
- EXPECT_TRUE(std::isinf(timedItem->takeTimeToNextIteration()));
-}
-
-}
diff --git a/chromium/third_party/WebKit/Source/core/animation/Timing.h b/chromium/third_party/WebKit/Source/core/animation/Timing.h
index 9a3bc4e6235..e862f653aec 100644
--- a/chromium/third_party/WebKit/Source/core/animation/Timing.h
+++ b/chromium/third_party/WebKit/Source/core/animation/Timing.h
@@ -31,7 +31,7 @@
#ifndef Timing_h
#define Timing_h
-#include "core/platform/animation/TimingFunction.h"
+#include "platform/animation/TimingFunction.h"
#include "wtf/MathExtras.h"
#include "wtf/RefPtr.h"
@@ -39,6 +39,7 @@ namespace WebCore {
struct Timing {
enum FillMode {
+ FillModeAuto,
FillModeNone,
FillModeForwards,
FillModeBackwards,
@@ -52,37 +53,43 @@ struct Timing {
PlaybackDirectionAlternateReverse
};
+ static const Timing& defaults()
+ {
+ DEFINE_STATIC_LOCAL(Timing, timing, ());
+ return timing;
+ }
+
Timing()
: startDelay(0)
- , fillMode(FillModeForwards)
+ , endDelay(0)
+ , fillMode(FillModeAuto)
, iterationStart(0)
, iterationCount(1)
- , hasIterationDuration(false)
- , iterationDuration(0)
+ , iterationDuration(std::numeric_limits<double>::quiet_NaN())
, playbackRate(1)
, direction(PlaybackDirectionNormal)
- , timingFunction(LinearTimingFunction::create())
+ , timingFunction(LinearTimingFunction::shared())
{
}
void assertValid() const
{
ASSERT(std::isfinite(startDelay));
+ ASSERT(std::isfinite(endDelay));
ASSERT(std::isfinite(iterationStart));
ASSERT(iterationStart >= 0);
ASSERT(iterationCount >= 0);
- ASSERT(iterationDuration >= 0);
+ ASSERT(std::isnan(iterationDuration) || iterationDuration >= 0);
ASSERT(std::isfinite(playbackRate));
ASSERT(timingFunction);
}
double startDelay;
+ double endDelay;
FillMode fillMode;
double iterationStart;
double iterationCount;
- bool hasIterationDuration;
double iterationDuration;
- // FIXME: Add activeDuration.
double playbackRate;
PlaybackDirection direction;
RefPtr<TimingFunction> timingFunction;
diff --git a/chromium/third_party/WebKit/Source/core/animation/Timing.idl b/chromium/third_party/WebKit/Source/core/animation/Timing.idl
new file mode 100644
index 00000000000..49e93e1d61f
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/Timing.idl
@@ -0,0 +1,29 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+[
+ RuntimeEnabled=WebAnimationsAPI,
+ ImplementedAs=AnimationNodeTiming,
+ WillBeGarbageCollected,
+] interface Timing {
+ attribute double delay;
+ attribute double endDelay;
+ attribute DOMString fill;
+ attribute double iterationStart;
+ attribute double iterations;
+
+ // FIXME: This uses a NamedPropertyGetter to implement the 'duration' attribute
+ // because duration has a union type (which is tricky to do with an attribute).
+ // Fix will be in a follow-up patch if there is a better solution.
+ [NotEnumerable, ImplementedAs=getDuration] getter (double or DOMString) (DOMString name);
+
+ // FIXME: If the user calls animation.specified.duration = "" (empty string) then duration
+ // gets set to 0 (This is correct behavior for IDL). Correct result is for duration to
+ // be set to 'auto'.
+ [TypeChecking=Interface|Nullable, ImplementedAs=setDuration] setter double (DOMString name, double duration);
+
+ attribute double playbackRate;
+ attribute DOMString direction;
+ attribute DOMString easing;
+};
diff --git a/chromium/third_party/WebKit/Source/core/animation/TimedItemCalculations.h b/chromium/third_party/WebKit/Source/core/animation/TimingCalculations.h
index 28a6228554a..1954e42b665 100644
--- a/chromium/third_party/WebKit/Source/core/animation/TimedItemCalculations.h
+++ b/chromium/third_party/WebKit/Source/core/animation/TimingCalculations.h
@@ -28,10 +28,10 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef TimedItemCalculations_h
-#define TimedItemCalculations_h
+#ifndef TimingCalculations_h
+#define TimingCalculations_h
-#include "core/animation/TimedItem.h"
+#include "core/animation/AnimationNode.h"
#include "core/animation/Timing.h"
#include "platform/animation/AnimationUtilities.h"
#include "wtf/MathExtras.h"
@@ -45,26 +45,26 @@ static inline double multiplyZeroAlwaysGivesZero(double x, double y)
return x && y ? x * y : 0;
}
-static inline TimedItem::Phase calculatePhase(double activeDuration, double localTime, const Timing& specified)
+static inline AnimationNode::Phase calculatePhase(double activeDuration, double localTime, const Timing& specified)
{
ASSERT(activeDuration >= 0);
if (isNull(localTime))
- return TimedItem::PhaseNone;
+ return AnimationNode::PhaseNone;
if (localTime < specified.startDelay)
- return TimedItem::PhaseBefore;
+ return AnimationNode::PhaseBefore;
if (localTime >= specified.startDelay + activeDuration)
- return TimedItem::PhaseAfter;
- return TimedItem::PhaseActive;
+ return AnimationNode::PhaseAfter;
+ return AnimationNode::PhaseActive;
}
-static inline bool isActiveInParentPhase(TimedItem::Phase parentPhase, Timing::FillMode fillMode)
+static inline bool isActiveInParentPhase(AnimationNode::Phase parentPhase, Timing::FillMode fillMode)
{
switch (parentPhase) {
- case TimedItem::PhaseBefore:
+ case AnimationNode::PhaseBefore:
return fillMode == Timing::FillModeBackwards || fillMode == Timing::FillModeBoth;
- case TimedItem::PhaseActive:
+ case AnimationNode::PhaseActive:
return true;
- case TimedItem::PhaseAfter:
+ case AnimationNode::PhaseAfter:
return fillMode == Timing::FillModeForwards || fillMode == Timing::FillModeBoth;
default:
ASSERT_NOT_REACHED();
@@ -72,25 +72,25 @@ static inline bool isActiveInParentPhase(TimedItem::Phase parentPhase, Timing::F
}
}
-static inline double calculateActiveTime(double activeDuration, double localTime, TimedItem::Phase parentPhase, TimedItem::Phase phase, const Timing& specified)
+static inline double calculateActiveTime(double activeDuration, Timing::FillMode fillMode, double localTime, AnimationNode::Phase parentPhase, AnimationNode::Phase phase, const Timing& specified)
{
ASSERT(activeDuration >= 0);
ASSERT(phase == calculatePhase(activeDuration, localTime, specified));
switch (phase) {
- case TimedItem::PhaseBefore:
- if (specified.fillMode == Timing::FillModeBackwards || specified.fillMode == Timing::FillModeBoth)
+ case AnimationNode::PhaseBefore:
+ if (fillMode == Timing::FillModeBackwards || fillMode == Timing::FillModeBoth)
return 0;
return nullValue();
- case TimedItem::PhaseActive:
- if (isActiveInParentPhase(parentPhase, specified.fillMode))
+ case AnimationNode::PhaseActive:
+ if (isActiveInParentPhase(parentPhase, fillMode))
return localTime - specified.startDelay;
return nullValue();
- case TimedItem::PhaseAfter:
- if (specified.fillMode == Timing::FillModeForwards || specified.fillMode == Timing::FillModeBoth)
+ case AnimationNode::PhaseAfter:
+ if (fillMode == Timing::FillModeForwards || fillMode == Timing::FillModeBoth)
return activeDuration;
return nullValue();
- case TimedItem::PhaseNone:
+ case AnimationNode::PhaseNone:
ASSERT(isNull(localTime));
return nullValue();
default:
@@ -190,9 +190,7 @@ static inline double calculateTransformedTime(double currentIteration, double it
return directedTime;
double timeFraction = directedTime / iterationDuration;
ASSERT(timeFraction >= 0 && timeFraction <= 1);
- return specified.timingFunction
- ? multiplyZeroAlwaysGivesZero(iterationDuration, specified.timingFunction->evaluate(timeFraction, accuracyForDuration(iterationDuration)))
- : directedTime;
+ return multiplyZeroAlwaysGivesZero(iterationDuration, specified.timingFunction->evaluate(timeFraction, accuracyForDuration(iterationDuration)));
}
} // namespace WebCore
diff --git a/chromium/third_party/WebKit/Source/core/animation/TimedItemCalculationsTest.cpp b/chromium/third_party/WebKit/Source/core/animation/TimingCalculationsTest.cpp
index 6e053cdde8f..ffd22058166 100644
--- a/chromium/third_party/WebKit/Source/core/animation/TimedItemCalculationsTest.cpp
+++ b/chromium/third_party/WebKit/Source/core/animation/TimingCalculationsTest.cpp
@@ -29,7 +29,7 @@
*/
#include "config.h"
-#include "core/animation/TimedItemCalculations.h"
+#include "core/animation/TimingCalculations.h"
#include <gtest/gtest.h>
@@ -37,55 +37,42 @@ using namespace WebCore;
namespace {
-TEST(AnimationTimedItemCalculationsTest, ActiveTime)
+TEST(AnimationTimingCalculationsTest, ActiveTime)
{
Timing timing;
- // calculateActiveTime(activeDuration, localTime, parentPhase, phase, timing)
+ // calculateActiveTime(activeDuration, fillMode, localTime, parentPhase, phase, timing)
// Before Phase
timing.startDelay = 10;
- timing.fillMode = Timing::FillModeForwards;
- EXPECT_TRUE(isNull(calculateActiveTime(20, 0, TimedItem::PhaseActive, TimedItem::PhaseBefore, timing)));
- timing.fillMode = Timing::FillModeNone;
- EXPECT_TRUE(isNull(calculateActiveTime(20, 0, TimedItem::PhaseActive, TimedItem::PhaseBefore, timing)));
- timing.fillMode = Timing::FillModeBackwards;
- EXPECT_EQ(0, calculateActiveTime(20, 0, TimedItem::PhaseActive, TimedItem::PhaseBefore, timing));
- timing.fillMode = Timing::FillModeBoth;
- EXPECT_EQ(0, calculateActiveTime(20, 0, TimedItem::PhaseActive, TimedItem::PhaseBefore, timing));
+ EXPECT_TRUE(isNull(calculateActiveTime(20, Timing::FillModeForwards, 0, AnimationNode::PhaseActive, AnimationNode::PhaseBefore, timing)));
+ EXPECT_TRUE(isNull(calculateActiveTime(20, Timing::FillModeNone, 0, AnimationNode::PhaseActive, AnimationNode::PhaseBefore, timing)));
+ EXPECT_EQ(0, calculateActiveTime(20, Timing::FillModeBackwards, 0, AnimationNode::PhaseActive, AnimationNode::PhaseBefore, timing));
+ EXPECT_EQ(0, calculateActiveTime(20, Timing::FillModeBoth, 0, AnimationNode::PhaseActive, AnimationNode::PhaseBefore, timing));
// Active Phase
timing.startDelay = 10;
// Active, and parent Before
- timing.fillMode = Timing::FillModeNone;
- EXPECT_TRUE(isNull(calculateActiveTime(20, 15, TimedItem::PhaseBefore, TimedItem::PhaseActive, timing)));
- timing.fillMode = Timing::FillModeForwards;
- EXPECT_TRUE(isNull(calculateActiveTime(20, 15, TimedItem::PhaseBefore, TimedItem::PhaseActive, timing)));
+ EXPECT_TRUE(isNull(calculateActiveTime(20, Timing::FillModeNone, 15, AnimationNode::PhaseBefore, AnimationNode::PhaseActive, timing)));
+ EXPECT_TRUE(isNull(calculateActiveTime(20, Timing::FillModeForwards, 15, AnimationNode::PhaseBefore, AnimationNode::PhaseActive, timing)));
// Active, and parent After
- timing.fillMode = Timing::FillModeNone;
- EXPECT_TRUE(isNull(calculateActiveTime(20, 15, TimedItem::PhaseAfter, TimedItem::PhaseActive, timing)));
- timing.fillMode = Timing::FillModeBackwards;
- EXPECT_TRUE(isNull(calculateActiveTime(20, 15, TimedItem::PhaseAfter, TimedItem::PhaseActive, timing)));
+ EXPECT_TRUE(isNull(calculateActiveTime(20, Timing::FillModeNone, 15, AnimationNode::PhaseAfter, AnimationNode::PhaseActive, timing)));
+ EXPECT_TRUE(isNull(calculateActiveTime(20, Timing::FillModeBackwards, 15, AnimationNode::PhaseAfter, AnimationNode::PhaseActive, timing)));
// Active, and parent Active
- timing.fillMode = Timing::FillModeForwards;
- EXPECT_EQ(5, calculateActiveTime(20, 15, TimedItem::PhaseActive, TimedItem::PhaseActive, timing));
+ EXPECT_EQ(5, calculateActiveTime(20, Timing::FillModeForwards, 15, AnimationNode::PhaseActive, AnimationNode::PhaseActive, timing));
// After Phase
timing.startDelay = 10;
- timing.fillMode = Timing::FillModeForwards;
- EXPECT_EQ(21, calculateActiveTime(21, 45, TimedItem::PhaseActive, TimedItem::PhaseAfter, timing));
- timing.fillMode = Timing::FillModeBoth;
- EXPECT_EQ(21, calculateActiveTime(21, 45, TimedItem::PhaseActive, TimedItem::PhaseAfter, timing));
- timing.fillMode = Timing::FillModeBackwards;
- EXPECT_TRUE(isNull(calculateActiveTime(21, 45, TimedItem::PhaseActive, TimedItem::PhaseAfter, timing)));
- timing.fillMode = Timing::FillModeNone;
- EXPECT_TRUE(isNull(calculateActiveTime(21, 45, TimedItem::PhaseActive, TimedItem::PhaseAfter, timing)));
+ EXPECT_EQ(21, calculateActiveTime(21, Timing::FillModeForwards, 45, AnimationNode::PhaseActive, AnimationNode::PhaseAfter, timing));
+ EXPECT_EQ(21, calculateActiveTime(21, Timing::FillModeBoth, 45, AnimationNode::PhaseActive, AnimationNode::PhaseAfter, timing));
+ EXPECT_TRUE(isNull(calculateActiveTime(21, Timing::FillModeBackwards, 45, AnimationNode::PhaseActive, AnimationNode::PhaseAfter, timing)));
+ EXPECT_TRUE(isNull(calculateActiveTime(21, Timing::FillModeNone, 45, AnimationNode::PhaseActive, AnimationNode::PhaseAfter, timing)));
// None
- EXPECT_TRUE(isNull(calculateActiveTime(32, nullValue(), TimedItem::PhaseNone, TimedItem::PhaseNone, timing)));
+ EXPECT_TRUE(isNull(calculateActiveTime(32, Timing::FillModeNone, nullValue(), AnimationNode::PhaseNone, AnimationNode::PhaseNone, timing)));
}
-TEST(AnimationTimedItemCalculationsTest, ScaledActiveTime)
+TEST(AnimationTimingCalculationsTest, ScaledActiveTime)
{
Timing timing;
@@ -111,7 +98,7 @@ TEST(AnimationTimedItemCalculationsTest, ScaledActiveTime)
EXPECT_EQ(std::numeric_limits<double>::infinity(), calculateScaledActiveTime(std::numeric_limits<double>::infinity(), std::numeric_limits<double>::infinity(), 0, timing));
}
-TEST(AnimationTimedItemCalculationsTest, IterationTime)
+TEST(AnimationTimingCalculationsTest, IterationTime)
{
Timing timing;
@@ -131,7 +118,7 @@ TEST(AnimationTimedItemCalculationsTest, IterationTime)
EXPECT_EQ(8, calculateIterationTime(12, 120, 20, 7, timing));
}
-TEST(AnimationTimedItemCalculationsTest, CurrentIteration)
+TEST(AnimationTimingCalculationsTest, CurrentIteration)
{
Timing timing;
@@ -152,7 +139,7 @@ TEST(AnimationTimedItemCalculationsTest, CurrentIteration)
EXPECT_EQ(3, calculateCurrentIteration(3.2, 3.1, 10, timing));
}
-TEST(AnimationTimedItemCalculationsTest, DirectedTime)
+TEST(AnimationTimingCalculationsTest, DirectedTime)
{
Timing timing;
@@ -183,7 +170,7 @@ TEST(AnimationTimedItemCalculationsTest, DirectedTime)
EXPECT_EQ(3, calculateDirectedTime(2, 20, 17, timing));
}
-TEST(AnimationTimedItemCalculationsTest, TransformedTime)
+TEST(AnimationTimingCalculationsTest, TransformedTime)
{
Timing timing;
@@ -197,18 +184,18 @@ TEST(AnimationTimedItemCalculationsTest, TransformedTime)
EXPECT_EQ(12, calculateTransformedTime(1, 20, 12, timing));
// PlaybackDirectionForwards with timing function
- timing.timingFunction = StepsTimingFunction::create(4, false /* stepAtStart */);
+ timing.timingFunction = StepsTimingFunction::create(4, StepsTimingFunction::StepAtEnd);
EXPECT_EQ(10, calculateTransformedTime(0, 20, 12, timing));
EXPECT_EQ(10, calculateTransformedTime(1, 20, 12, timing));
// PlaybackDirectionReverse
- timing.timingFunction = 0;
+ timing.timingFunction = Timing::defaults().timingFunction;
timing.direction = Timing::PlaybackDirectionReverse;
EXPECT_EQ(8, calculateTransformedTime(0, 20, 12, timing));
EXPECT_EQ(8, calculateTransformedTime(1, 20, 12, timing));
// PlaybackDirectionReverse with timing function
- timing.timingFunction = StepsTimingFunction::create(4, false /* stepAtStart */);
+ timing.timingFunction = StepsTimingFunction::create(4, StepsTimingFunction::StepAtEnd);
EXPECT_EQ(5, calculateTransformedTime(0, 20, 12, timing));
EXPECT_EQ(5, calculateTransformedTime(1, 20, 12, timing));
diff --git a/chromium/third_party/WebKit/Source/core/animation/TimingInput.cpp b/chromium/third_party/WebKit/Source/core/animation/TimingInput.cpp
new file mode 100644
index 00000000000..f9eeedaa668
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/TimingInput.cpp
@@ -0,0 +1,154 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "config.h"
+#include "core/animation/TimingInput.h"
+
+#include "bindings/v8/Dictionary.h"
+#include "core/css/parser/BisonCSSParser.h"
+#include "core/css/resolver/CSSToStyleMap.h"
+
+namespace WebCore {
+
+void TimingInput::setStartDelay(Timing& timing, double startDelay)
+{
+ if (std::isfinite(startDelay))
+ timing.startDelay = startDelay / 1000;
+ else
+ timing.startDelay = Timing::defaults().startDelay;
+}
+
+void TimingInput::setEndDelay(Timing& timing, double endDelay)
+{
+ if (std::isfinite(endDelay))
+ timing.endDelay = endDelay / 1000;
+ else
+ timing.endDelay = Timing::defaults().endDelay;
+}
+
+void TimingInput::setFillMode(Timing& timing, const String& fillMode)
+{
+ if (fillMode == "none") {
+ timing.fillMode = Timing::FillModeNone;
+ } else if (fillMode == "backwards") {
+ timing.fillMode = Timing::FillModeBackwards;
+ } else if (fillMode == "both") {
+ timing.fillMode = Timing::FillModeBoth;
+ } else if (fillMode == "forwards") {
+ timing.fillMode = Timing::FillModeForwards;
+ } else {
+ timing.fillMode = Timing::defaults().fillMode;
+ }
+}
+
+void TimingInput::setIterationStart(Timing& timing, double iterationStart)
+{
+ if (std::isfinite(iterationStart))
+ timing.iterationStart = std::max<double>(iterationStart, 0);
+ else
+ timing.iterationStart = Timing::defaults().iterationStart;
+}
+
+void TimingInput::setIterationCount(Timing& timing, double iterationCount)
+{
+ if (!std::isnan(iterationCount))
+ timing.iterationCount = std::max<double>(iterationCount, 0);
+ else
+ timing.iterationCount = Timing::defaults().iterationCount;
+}
+
+void TimingInput::setIterationDuration(Timing& timing, double iterationDuration)
+{
+ if (!std::isnan(iterationDuration) && iterationDuration >= 0)
+ timing.iterationDuration = iterationDuration / 1000;
+ else
+ timing.iterationDuration = Timing::defaults().iterationDuration;
+}
+
+void TimingInput::setPlaybackRate(Timing& timing, double playbackRate)
+{
+ if (std::isfinite(playbackRate))
+ timing.playbackRate = playbackRate;
+ else
+ timing.playbackRate = Timing::defaults().playbackRate;
+}
+
+void TimingInput::setPlaybackDirection(Timing& timing, const String& direction)
+{
+ if (direction == "reverse") {
+ timing.direction = Timing::PlaybackDirectionReverse;
+ } else if (direction == "alternate") {
+ timing.direction = Timing::PlaybackDirectionAlternate;
+ } else if (direction == "alternate-reverse") {
+ timing.direction = Timing::PlaybackDirectionAlternateReverse;
+ } else {
+ timing.direction = Timing::defaults().direction;
+ }
+}
+
+void TimingInput::setTimingFunction(Timing& timing, const String& timingFunctionString)
+{
+ if (RefPtrWillBeRawPtr<CSSValue> timingFunctionValue = BisonCSSParser::parseAnimationTimingFunctionValue(timingFunctionString))
+ timing.timingFunction = CSSToStyleMap::mapAnimationTimingFunction(timingFunctionValue.get(), true);
+ else
+ timing.timingFunction = Timing::defaults().timingFunction;
+}
+
+Timing TimingInput::convert(const Dictionary& timingInputDictionary)
+{
+ Timing result;
+
+ // FIXME: This method needs to be refactored to handle invalid
+ // null, NaN, Infinity values better.
+ // See: http://www.w3.org/TR/WebIDL/#es-double
+ double startDelay = Timing::defaults().startDelay;
+ timingInputDictionary.get("delay", startDelay);
+ setStartDelay(result, startDelay);
+
+ double endDelay = Timing::defaults().endDelay;
+ timingInputDictionary.get("endDelay", endDelay);
+ setEndDelay(result, endDelay);
+
+ String fillMode;
+ timingInputDictionary.get("fill", fillMode);
+ setFillMode(result, fillMode);
+
+ double iterationStart = Timing::defaults().iterationStart;
+ timingInputDictionary.get("iterationStart", iterationStart);
+ setIterationStart(result, iterationStart);
+
+ double iterationCount = Timing::defaults().iterationCount;
+ timingInputDictionary.get("iterations", iterationCount);
+ setIterationCount(result, iterationCount);
+
+ double iterationDuration = 0;
+ if (timingInputDictionary.get("duration", iterationDuration)) {
+ setIterationDuration(result, iterationDuration);
+ }
+
+ double playbackRate = Timing::defaults().playbackRate;
+ timingInputDictionary.get("playbackRate", playbackRate);
+ setPlaybackRate(result, playbackRate);
+
+ String direction;
+ timingInputDictionary.get("direction", direction);
+ setPlaybackDirection(result, direction);
+
+ String timingFunctionString;
+ timingInputDictionary.get("easing", timingFunctionString);
+ setTimingFunction(result, timingFunctionString);
+
+ result.assertValid();
+
+ return result;
+}
+
+Timing TimingInput::convert(double duration)
+{
+ Timing result;
+ setIterationDuration(result, duration);
+ return result;
+}
+
+} // namespace WebCore
diff --git a/chromium/third_party/WebKit/Source/core/animation/TimingInput.h b/chromium/third_party/WebKit/Source/core/animation/TimingInput.h
new file mode 100644
index 00000000000..c338201e092
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/TimingInput.h
@@ -0,0 +1,32 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef TimingInput_h
+#define TimingInput_h
+
+#include "core/animation/Timing.h"
+
+namespace WebCore {
+
+class Dictionary;
+
+class TimingInput {
+public:
+ static Timing convert(const Dictionary& timingInputDictionary);
+ static Timing convert(double duration);
+
+ static void setStartDelay(Timing&, double startDelay);
+ static void setEndDelay(Timing&, double endDelay);
+ static void setFillMode(Timing&, const String& fillMode);
+ static void setIterationStart(Timing&, double iterationStart);
+ static void setIterationCount(Timing&, double iterationCount);
+ static void setIterationDuration(Timing&, double iterationDuration);
+ static void setPlaybackRate(Timing&, double playbackRate);
+ static void setPlaybackDirection(Timing&, const String& direction);
+ static void setTimingFunction(Timing&, const String& timingFunctionString);
+};
+
+} // namespace WebCore
+
+#endif
diff --git a/chromium/third_party/WebKit/Source/core/animation/TimingInputTest.cpp b/chromium/third_party/WebKit/Source/core/animation/TimingInputTest.cpp
new file mode 100644
index 00000000000..57b6a0893bb
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/TimingInputTest.cpp
@@ -0,0 +1,181 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "config.h"
+#include "core/animation/TimingInput.h"
+
+#include "bindings/v8/Dictionary.h"
+#include "core/animation/AnimationNodeTiming.h"
+#include "core/animation/AnimationTestHelper.h"
+#include <gtest/gtest.h>
+#include <v8.h>
+
+namespace WebCore {
+
+class AnimationTimingInputTest : public ::testing::Test {
+protected:
+ AnimationTimingInputTest()
+ : m_isolate(v8::Isolate::GetCurrent())
+ , m_scope(m_isolate)
+ {
+ }
+
+ Timing applyTimingInputNumber(String timingProperty, double timingPropertyValue)
+ {
+ v8::Handle<v8::Object> timingInput = v8::Object::New(m_isolate);
+ setV8ObjectPropertyAsNumber(timingInput, timingProperty, timingPropertyValue);
+ Dictionary timingInputDictionary = Dictionary(v8::Handle<v8::Value>::Cast(timingInput), m_isolate);
+ return TimingInput::convert(timingInputDictionary);
+ }
+
+ Timing applyTimingInputString(String timingProperty, String timingPropertyValue)
+ {
+ v8::Handle<v8::Object> timingInput = v8::Object::New(m_isolate);
+ setV8ObjectPropertyAsString(timingInput, timingProperty, timingPropertyValue);
+ Dictionary timingInputDictionary = Dictionary(v8::Handle<v8::Value>::Cast(timingInput), m_isolate);
+ return TimingInput::convert(timingInputDictionary);
+ }
+
+ v8::Isolate* m_isolate;
+
+private:
+ V8TestingScope m_scope;
+};
+
+TEST_F(AnimationTimingInputTest, TimingInputStartDelay)
+{
+ EXPECT_EQ(1.1, applyTimingInputNumber("delay", 1100).startDelay);
+ EXPECT_EQ(-1, applyTimingInputNumber("delay", -1000).startDelay);
+ EXPECT_EQ(1, applyTimingInputString("delay", "1000").startDelay);
+ EXPECT_EQ(0, applyTimingInputString("delay", "1s").startDelay);
+ EXPECT_EQ(0, applyTimingInputString("delay", "Infinity").startDelay);
+ EXPECT_EQ(0, applyTimingInputString("delay", "-Infinity").startDelay);
+ EXPECT_EQ(0, applyTimingInputString("delay", "NaN").startDelay);
+ EXPECT_EQ(0, applyTimingInputString("delay", "rubbish").startDelay);
+}
+
+TEST_F(AnimationTimingInputTest, TimingInputEndDelay)
+{
+ EXPECT_EQ(10, applyTimingInputNumber("endDelay", 10000).endDelay);
+ EXPECT_EQ(-2.5, applyTimingInputNumber("endDelay", -2500).endDelay);
+}
+
+TEST_F(AnimationTimingInputTest, TimingInputFillMode)
+{
+ Timing::FillMode defaultFillMode = Timing::FillModeAuto;
+
+ EXPECT_EQ(Timing::FillModeAuto, applyTimingInputString("fill", "auto").fillMode);
+ EXPECT_EQ(Timing::FillModeForwards, applyTimingInputString("fill", "forwards").fillMode);
+ EXPECT_EQ(Timing::FillModeNone, applyTimingInputString("fill", "none").fillMode);
+ EXPECT_EQ(Timing::FillModeBackwards, applyTimingInputString("fill", "backwards").fillMode);
+ EXPECT_EQ(Timing::FillModeBoth, applyTimingInputString("fill", "both").fillMode);
+ EXPECT_EQ(defaultFillMode, applyTimingInputString("fill", "everything!").fillMode);
+ EXPECT_EQ(defaultFillMode, applyTimingInputString("fill", "backwardsandforwards").fillMode);
+ EXPECT_EQ(defaultFillMode, applyTimingInputNumber("fill", 2).fillMode);
+}
+
+TEST_F(AnimationTimingInputTest, TimingInputIterationStart)
+{
+ EXPECT_EQ(1.1, applyTimingInputNumber("iterationStart", 1.1).iterationStart);
+ EXPECT_EQ(0, applyTimingInputNumber("iterationStart", -1).iterationStart);
+ EXPECT_EQ(0, applyTimingInputString("iterationStart", "Infinity").iterationStart);
+ EXPECT_EQ(0, applyTimingInputString("iterationStart", "-Infinity").iterationStart);
+ EXPECT_EQ(0, applyTimingInputString("iterationStart", "NaN").iterationStart);
+ EXPECT_EQ(0, applyTimingInputString("iterationStart", "rubbish").iterationStart);
+}
+
+TEST_F(AnimationTimingInputTest, TimingInputIterationCount)
+{
+ EXPECT_EQ(2.1, applyTimingInputNumber("iterations", 2.1).iterationCount);
+ EXPECT_EQ(0, applyTimingInputNumber("iterations", -1).iterationCount);
+
+ Timing timing = applyTimingInputString("iterations", "Infinity");
+ EXPECT_TRUE(std::isinf(timing.iterationCount));
+ EXPECT_GT(timing.iterationCount, 0);
+
+ EXPECT_EQ(0, applyTimingInputString("iterations", "-Infinity").iterationCount);
+ EXPECT_EQ(1, applyTimingInputString("iterations", "NaN").iterationCount);
+ EXPECT_EQ(1, applyTimingInputString("iterations", "rubbish").iterationCount);
+}
+
+TEST_F(AnimationTimingInputTest, TimingInputIterationDuration)
+{
+ EXPECT_EQ(1.1, applyTimingInputNumber("duration", 1100).iterationDuration);
+ EXPECT_TRUE(std::isnan(applyTimingInputNumber("duration", -1000).iterationDuration));
+ EXPECT_EQ(1, applyTimingInputString("duration", "1000").iterationDuration);
+
+ Timing timing = applyTimingInputString("duration", "Infinity");
+ EXPECT_TRUE(std::isinf(timing.iterationDuration));
+ EXPECT_GT(timing.iterationDuration, 0);
+
+ EXPECT_TRUE(std::isnan(applyTimingInputString("duration", "-Infinity").iterationDuration));
+ EXPECT_TRUE(std::isnan(applyTimingInputString("duration", "NaN").iterationDuration));
+ EXPECT_TRUE(std::isnan(applyTimingInputString("duration", "auto").iterationDuration));
+ EXPECT_TRUE(std::isnan(applyTimingInputString("duration", "rubbish").iterationDuration));
+}
+
+TEST_F(AnimationTimingInputTest, TimingInputPlaybackRate)
+{
+ EXPECT_EQ(2.1, applyTimingInputNumber("playbackRate", 2.1).playbackRate);
+ EXPECT_EQ(-1, applyTimingInputNumber("playbackRate", -1).playbackRate);
+ EXPECT_EQ(1, applyTimingInputString("playbackRate", "Infinity").playbackRate);
+ EXPECT_EQ(1, applyTimingInputString("playbackRate", "-Infinity").playbackRate);
+ EXPECT_EQ(1, applyTimingInputString("playbackRate", "NaN").playbackRate);
+ EXPECT_EQ(1, applyTimingInputString("playbackRate", "rubbish").playbackRate);
+}
+
+TEST_F(AnimationTimingInputTest, TimingInputDirection)
+{
+ Timing::PlaybackDirection defaultPlaybackDirection = Timing::PlaybackDirectionNormal;
+
+ EXPECT_EQ(Timing::PlaybackDirectionNormal, applyTimingInputString("direction", "normal").direction);
+ EXPECT_EQ(Timing::PlaybackDirectionReverse, applyTimingInputString("direction", "reverse").direction);
+ EXPECT_EQ(Timing::PlaybackDirectionAlternate, applyTimingInputString("direction", "alternate").direction);
+ EXPECT_EQ(Timing::PlaybackDirectionAlternateReverse, applyTimingInputString("direction", "alternate-reverse").direction);
+ EXPECT_EQ(defaultPlaybackDirection, applyTimingInputString("direction", "rubbish").direction);
+ EXPECT_EQ(defaultPlaybackDirection, applyTimingInputNumber("direction", 2).direction);
+}
+
+TEST_F(AnimationTimingInputTest, TimingInputTimingFunction)
+{
+ const RefPtr<TimingFunction> defaultTimingFunction = LinearTimingFunction::shared();
+
+ EXPECT_EQ(*CubicBezierTimingFunction::preset(CubicBezierTimingFunction::Ease), *applyTimingInputString("easing", "ease").timingFunction);
+ EXPECT_EQ(*CubicBezierTimingFunction::preset(CubicBezierTimingFunction::EaseIn), *applyTimingInputString("easing", "ease-in").timingFunction);
+ EXPECT_EQ(*CubicBezierTimingFunction::preset(CubicBezierTimingFunction::EaseOut), *applyTimingInputString("easing", "ease-out").timingFunction);
+ EXPECT_EQ(*CubicBezierTimingFunction::preset(CubicBezierTimingFunction::EaseInOut), *applyTimingInputString("easing", "ease-in-out").timingFunction);
+ EXPECT_EQ(*LinearTimingFunction::shared(), *applyTimingInputString("easing", "linear").timingFunction);
+ EXPECT_EQ(*StepsTimingFunction::preset(StepsTimingFunction::Start), *applyTimingInputString("easing", "step-start").timingFunction);
+ EXPECT_EQ(*StepsTimingFunction::preset(StepsTimingFunction::Middle), *applyTimingInputString("easing", "step-middle").timingFunction);
+ EXPECT_EQ(*StepsTimingFunction::preset(StepsTimingFunction::End), *applyTimingInputString("easing", "step-end").timingFunction);
+ EXPECT_EQ(*CubicBezierTimingFunction::create(1, 1, 0.3, 0.3), *applyTimingInputString("easing", "cubic-bezier(1, 1, 0.3, 0.3)").timingFunction);
+ EXPECT_EQ(*StepsTimingFunction::create(3, StepsTimingFunction::StepAtStart), *applyTimingInputString("easing", "steps(3, start)").timingFunction);
+ EXPECT_EQ(*StepsTimingFunction::create(5, StepsTimingFunction::StepAtMiddle), *applyTimingInputString("easing", "steps(5, middle)").timingFunction);
+ EXPECT_EQ(*StepsTimingFunction::create(5, StepsTimingFunction::StepAtEnd), *applyTimingInputString("easing", "steps(5, end)").timingFunction);
+ EXPECT_EQ(*defaultTimingFunction, *applyTimingInputString("easing", "steps(5.6, end)").timingFunction);
+ EXPECT_EQ(*defaultTimingFunction, *applyTimingInputString("easing", "cubic-bezier(2, 2, 0.3, 0.3)").timingFunction);
+ EXPECT_EQ(*defaultTimingFunction, *applyTimingInputString("easing", "rubbish").timingFunction);
+ EXPECT_EQ(*defaultTimingFunction, *applyTimingInputNumber("easing", 2).timingFunction);
+ EXPECT_EQ(*defaultTimingFunction, *applyTimingInputString("easing", "initial").timingFunction);
+}
+
+TEST_F(AnimationTimingInputTest, TimingInputEmpty)
+{
+ Timing controlTiming;
+
+ v8::Handle<v8::Object> timingInput = v8::Object::New(m_isolate);
+ Dictionary timingInputDictionary = Dictionary(v8::Handle<v8::Value>::Cast(timingInput), m_isolate);
+ Timing updatedTiming = TimingInput::convert(timingInputDictionary);
+
+ EXPECT_EQ(controlTiming.startDelay, updatedTiming.startDelay);
+ EXPECT_EQ(controlTiming.fillMode, updatedTiming.fillMode);
+ EXPECT_EQ(controlTiming.iterationStart, updatedTiming.iterationStart);
+ EXPECT_EQ(controlTiming.iterationCount, updatedTiming.iterationCount);
+ EXPECT_TRUE(std::isnan(updatedTiming.iterationDuration));
+ EXPECT_EQ(controlTiming.playbackRate, updatedTiming.playbackRate);
+ EXPECT_EQ(controlTiming.direction, updatedTiming.direction);
+ EXPECT_EQ(*controlTiming.timingFunction, *updatedTiming.timingFunction);
+}
+
+} // namespace WebCore
diff --git a/chromium/third_party/WebKit/Source/core/animation/css/CSSAnimatableValueFactory.cpp b/chromium/third_party/WebKit/Source/core/animation/css/CSSAnimatableValueFactory.cpp
index 41138cdd177..b401069725e 100644
--- a/chromium/third_party/WebKit/Source/core/animation/css/CSSAnimatableValueFactory.cpp
+++ b/chromium/third_party/WebKit/Source/core/animation/css/CSSAnimatableValueFactory.cpp
@@ -31,7 +31,7 @@
#include "config.h"
#include "core/animation/css/CSSAnimatableValueFactory.h"
-#include "CSSValueKeywords.h"
+#include "core/CSSValueKeywords.h"
#include "core/animation/AnimatableClipPathOperation.h"
#include "core/animation/AnimatableColor.h"
#include "core/animation/AnimatableDouble.h"
@@ -41,6 +41,7 @@
#include "core/animation/AnimatableLengthBox.h"
#include "core/animation/AnimatableLengthBoxAndBool.h"
#include "core/animation/AnimatableLengthPoint.h"
+#include "core/animation/AnimatableLengthPoint3D.h"
#include "core/animation/AnimatableLengthSize.h"
#include "core/animation/AnimatableRepeatable.h"
#include "core/animation/AnimatableSVGLength.h"
@@ -61,23 +62,13 @@
namespace WebCore {
-static PassRefPtr<AnimatableValue> createFromLength(const Length& length, const RenderStyle& style)
+static PassRefPtrWillBeRawPtr<AnimatableValue> createFromLength(const Length& length, const RenderStyle& style)
{
switch (length.type()) {
case Fixed:
- return AnimatableLength::create(adjustFloatForAbsoluteZoom(length.value(), style), AnimatableLength::UnitTypePixels);
case Percent:
- return AnimatableLength::create(length.value(), AnimatableLength::UnitTypePercentage);
- case ViewportPercentageWidth:
- return AnimatableLength::create(length.value(), AnimatableLength::UnitTypeViewportWidth);
- case ViewportPercentageHeight:
- return AnimatableLength::create(length.value(), AnimatableLength::UnitTypeViewportHeight);
- case ViewportPercentageMin:
- return AnimatableLength::create(length.value(), AnimatableLength::UnitTypeViewportMin);
- case ViewportPercentageMax:
- return AnimatableLength::create(length.value(), AnimatableLength::UnitTypeViewportMax);
case Calculated:
- return AnimatableLength::create(CSSCalcValue::createExpressionNode(length.calculationValue()->expression(), style.effectiveZoom()));
+ return AnimatableLength::create(length, style.effectiveZoom());
case Auto:
case Intrinsic:
case MinIntrinsic:
@@ -85,18 +76,20 @@ static PassRefPtr<AnimatableValue> createFromLength(const Length& length, const
case MaxContent:
case FillAvailable:
case FitContent:
- return AnimatableUnknown::create(CSSPrimitiveValue::create(length));
+ return AnimatableUnknown::create(CSSPrimitiveValue::create(length, 1));
case Undefined:
return AnimatableUnknown::create(CSSValueNone);
case ExtendToZoom: // Does not apply to elements.
+ case DeviceWidth:
+ case DeviceHeight:
ASSERT_NOT_REACHED();
- return 0;
+ return nullptr;
}
ASSERT_NOT_REACHED();
- return 0;
+ return nullptr;
}
-static PassRefPtr<AnimatableValue> createFromLineHeight(const Length& length, const RenderStyle& style)
+static PassRefPtrWillBeRawPtr<AnimatableValue> createFromLineHeight(const Length& length, const RenderStyle& style)
{
if (length.type() == Percent) {
double value = length.value();
@@ -108,12 +101,12 @@ static PassRefPtr<AnimatableValue> createFromLineHeight(const Length& length, co
return createFromLength(length, style);
}
-inline static PassRefPtr<AnimatableValue> createFromDouble(double value, AnimatableDouble::Constraint constraint = AnimatableDouble::Unconstrained)
+inline static PassRefPtrWillBeRawPtr<AnimatableValue> createFromDouble(double value, AnimatableDouble::Constraint constraint = AnimatableDouble::Unconstrained)
{
return AnimatableDouble::create(value, constraint);
}
-inline static PassRefPtr<AnimatableValue> createFromLengthBox(const LengthBox& lengthBox, const RenderStyle& style)
+inline static PassRefPtrWillBeRawPtr<AnimatableValue> createFromLengthBox(const LengthBox& lengthBox, const RenderStyle& style)
{
return AnimatableLengthBox::create(
createFromLength(lengthBox.left(), style),
@@ -122,14 +115,14 @@ inline static PassRefPtr<AnimatableValue> createFromLengthBox(const LengthBox& l
createFromLength(lengthBox.bottom(), style));
}
-static PassRefPtr<AnimatableValue> createFromBorderImageLength(const BorderImageLength& borderImageLength, const RenderStyle& style)
+static PassRefPtrWillBeRawPtr<AnimatableValue> createFromBorderImageLength(const BorderImageLength& borderImageLength, const RenderStyle& style)
{
if (borderImageLength.isNumber())
return createFromDouble(borderImageLength.number());
return createFromLength(borderImageLength.length(), style);
}
-inline static PassRefPtr<AnimatableValue> createFromBorderImageLengthBox(const BorderImageLengthBox& borderImageLengthBox, const RenderStyle& style)
+inline static PassRefPtrWillBeRawPtr<AnimatableValue> createFromBorderImageLengthBox(const BorderImageLengthBox& borderImageLengthBox, const RenderStyle& style)
{
return AnimatableLengthBox::create(
createFromBorderImageLength(borderImageLengthBox.left(), style),
@@ -138,35 +131,37 @@ inline static PassRefPtr<AnimatableValue> createFromBorderImageLengthBox(const B
createFromBorderImageLength(borderImageLengthBox.bottom(), style));
}
-inline static PassRefPtr<AnimatableValue> createFromLengthBoxAndBool(const LengthBox lengthBox, const bool flag, const RenderStyle& style)
+inline static PassRefPtrWillBeRawPtr<AnimatableValue> createFromLengthBoxAndBool(const LengthBox lengthBox, const bool flag, const RenderStyle& style)
{
return AnimatableLengthBoxAndBool::create(
createFromLengthBox(lengthBox, style),
flag);
}
-inline static PassRefPtr<AnimatableValue> createFromLengthPoint(const LengthPoint& lengthPoint, const RenderStyle& style)
+inline static PassRefPtrWillBeRawPtr<AnimatableValue> createFromLengthPoint(const LengthPoint& lengthPoint, const RenderStyle& style)
{
return AnimatableLengthPoint::create(
createFromLength(lengthPoint.x(), style),
createFromLength(lengthPoint.y(), style));
}
-inline static PassRefPtr<AnimatableValue> createFromLengthSize(const LengthSize& lengthSize, const RenderStyle& style)
+inline static PassRefPtrWillBeRawPtr<AnimatableValue> createFromLengthSize(const LengthSize& lengthSize, const RenderStyle& style)
{
return AnimatableLengthSize::create(
createFromLength(lengthSize.width(), style),
createFromLength(lengthSize.height(), style));
}
-inline static PassRefPtr<AnimatableValue> createFromStyleImage(StyleImage* image)
+inline static PassRefPtrWillBeRawPtr<AnimatableValue> createFromStyleImage(StyleImage* image)
{
- if (image)
- return AnimatableImage::create(image);
+ if (image) {
+ if (RefPtrWillBeRawPtr<CSSValue> cssValue = image->cssValue())
+ return AnimatableImage::create(cssValue.release());
+ }
return AnimatableUnknown::create(CSSValueNone);
}
-inline static PassRefPtr<AnimatableValue> createFromFillSize(const FillSize& fillSize, const RenderStyle& style)
+inline static PassRefPtrWillBeRawPtr<AnimatableValue> createFromFillSize(const FillSize& fillSize, const RenderStyle& style)
{
switch (fillSize.type) {
case SizeLength:
@@ -177,15 +172,22 @@ inline static PassRefPtr<AnimatableValue> createFromFillSize(const FillSize& fil
return AnimatableUnknown::create(CSSPrimitiveValue::create(fillSize.type));
default:
ASSERT_NOT_REACHED();
- return 0;
+ return nullptr;
}
}
+inline static PassRefPtrWillBeRawPtr<AnimatableValue> createFromBackgroundPosition(const Length& length, bool originIsSet, BackgroundEdgeOrigin origin, const RenderStyle& style)
+{
+ if (!originIsSet || origin == LeftEdge || origin == TopEdge)
+ return createFromLength(length, style);
+ return createFromLength(length.subtractFromOneHundredPercent(), style);
+}
+
template<CSSPropertyID property>
-inline static PassRefPtr<AnimatableValue> createFromFillLayers(const FillLayer* fillLayer, const RenderStyle& style)
+inline static PassRefPtrWillBeRawPtr<AnimatableValue> createFromFillLayers(const FillLayer* fillLayer, const RenderStyle& style)
{
ASSERT(fillLayer);
- Vector<RefPtr<AnimatableValue> > values;
+ WillBeHeapVector<RefPtrWillBeMember<AnimatableValue> > values;
while (fillLayer) {
if (property == CSSPropertyBackgroundImage || property == CSSPropertyWebkitMaskImage) {
if (!fillLayer->isImageSet())
@@ -194,11 +196,11 @@ inline static PassRefPtr<AnimatableValue> createFromFillLayers(const FillLayer*
} else if (property == CSSPropertyBackgroundPositionX || property == CSSPropertyWebkitMaskPositionX) {
if (!fillLayer->isXPositionSet())
break;
- values.append(createFromLength(fillLayer->xPosition(), style));
+ values.append(createFromBackgroundPosition(fillLayer->xPosition(), fillLayer->isBackgroundXOriginSet(), fillLayer->backgroundXOrigin(), style));
} else if (property == CSSPropertyBackgroundPositionY || property == CSSPropertyWebkitMaskPositionY) {
if (!fillLayer->isYPositionSet())
break;
- values.append(createFromLength(fillLayer->yPosition(), style));
+ values.append(createFromBackgroundPosition(fillLayer->yPosition(), fillLayer->isBackgroundYOriginSet(), fillLayer->backgroundYOrigin(), style));
} else if (property == CSSPropertyBackgroundSize || property == CSSPropertyWebkitMaskSize) {
if (!fillLayer->isSizeSet())
break;
@@ -211,42 +213,56 @@ inline static PassRefPtr<AnimatableValue> createFromFillLayers(const FillLayer*
return AnimatableRepeatable::create(values);
}
-PassRefPtr<AnimatableValue> CSSAnimatableValueFactory::createFromColor(CSSPropertyID property, const RenderStyle& style)
+PassRefPtrWillBeRawPtr<AnimatableValue> CSSAnimatableValueFactory::createFromColor(CSSPropertyID property, const RenderStyle& style)
{
Color color = style.colorIncludingFallback(property, false);
Color visitedLinkColor = style.colorIncludingFallback(property, true);
- Color fallbackColor = style.color();
- Color fallbackVisitedLinkColor = style.visitedLinkColor();
- Color resolvedColor;
+ return AnimatableColor::create(color, visitedLinkColor);
+}
+
+inline static PassRefPtrWillBeRawPtr<AnimatableValue> createFromShapeValue(ShapeValue* value)
+{
+ if (value)
+ return AnimatableShapeValue::create(value);
+ return AnimatableUnknown::create(CSSValueNone);
+}
- if (property == CSSPropertyBackgroundColor) {
- // For background-color, invalid color means transparent and not currentColor.
- fallbackColor = Color::transparent;
- fallbackVisitedLinkColor = Color::transparent;
+static double fontWeightToDouble(FontWeight fontWeight)
+{
+ switch (fontWeight) {
+ case FontWeight100:
+ return 100;
+ case FontWeight200:
+ return 200;
+ case FontWeight300:
+ return 300;
+ case FontWeight400:
+ return 400;
+ case FontWeight500:
+ return 500;
+ case FontWeight600:
+ return 600;
+ case FontWeight700:
+ return 700;
+ case FontWeight800:
+ return 800;
+ case FontWeight900:
+ return 900;
}
- if (color.isValid())
- resolvedColor = color;
- else
- resolvedColor = fallbackColor;
- Color resolvedVisitedLinkColor;
- if (visitedLinkColor.isValid())
- resolvedVisitedLinkColor = visitedLinkColor;
- else
- resolvedVisitedLinkColor = fallbackVisitedLinkColor;
- return AnimatableColor::create(resolvedColor, resolvedVisitedLinkColor);
+ ASSERT_NOT_REACHED();
+ return 400;
}
-inline static PassRefPtr<AnimatableValue> createFromShapeValue(ShapeValue* value)
+static PassRefPtrWillBeRawPtr<AnimatableValue> createFromFontWeight(FontWeight fontWeight)
{
- if (value)
- return AnimatableShapeValue::create(value);
- return AnimatableUnknown::create(CSSValueAuto);
+ return createFromDouble(fontWeightToDouble(fontWeight));
}
// FIXME: Generate this function.
-PassRefPtr<AnimatableValue> CSSAnimatableValueFactory::create(CSSPropertyID property, const RenderStyle& style)
+PassRefPtrWillBeRawPtr<AnimatableValue> CSSAnimatableValueFactory::create(CSSPropertyID property, const RenderStyle& style)
{
+ ASSERT(CSSAnimations::isAnimatableProperty(property));
switch (property) {
case CSSPropertyBackgroundColor:
return createFromColor(property, style);
@@ -307,7 +323,10 @@ PassRefPtr<AnimatableValue> CSSAnimatableValueFactory::create(CSSPropertyID prop
case CSSPropertyFillOpacity:
return createFromDouble(style.fillOpacity());
case CSSPropertyFill:
- return AnimatableSVGPaint::create(style.svgStyle()->fillPaintType(), style.svgStyle()->fillPaintColor(), style.svgStyle()->fillPaintUri());
+ return AnimatableSVGPaint::create(
+ style.svgStyle()->fillPaintType(), style.svgStyle()->visitedLinkFillPaintType(),
+ style.svgStyle()->fillPaintColor(), style.svgStyle()->visitedLinkFillPaintColor(),
+ style.svgStyle()->fillPaintUri(), style.svgStyle()->visitedLinkFillPaintUri());
case CSSPropertyFlexGrow:
return createFromDouble(style.flexGrow(), AnimatableDouble::InterpolationIsNonContinuousWithZero);
case CSSPropertyFlexShrink:
@@ -324,10 +343,10 @@ PassRefPtr<AnimatableValue> CSSAnimatableValueFactory::create(CSSPropertyID prop
// FIXME: Should we introduce an option to pass the computed font size here, allowing consumers to
// enable text zoom rather than Text Autosizing? See http://crbug.com/227545.
return createFromDouble(style.specifiedFontSize());
+ case CSSPropertyFontWeight:
+ return createFromFontWeight(style.fontWeight());
case CSSPropertyHeight:
return createFromLength(style.height(), style);
- case CSSPropertyKerning:
- return AnimatableSVGLength::create(style.kerning());
case CSSPropertyLightingColor:
return createFromColor(property, style);
case CSSPropertyListStyleImage:
@@ -391,9 +410,12 @@ PassRefPtr<AnimatableValue> CSSAnimatableValueFactory::create(CSSPropertyID prop
case CSSPropertyStrokeOpacity:
return createFromDouble(style.strokeOpacity());
case CSSPropertyStroke:
- return AnimatableSVGPaint::create(style.svgStyle()->strokePaintType(), style.svgStyle()->strokePaintColor(), style.svgStyle()->strokePaintUri());
+ return AnimatableSVGPaint::create(
+ style.svgStyle()->strokePaintType(), style.svgStyle()->visitedLinkStrokePaintType(),
+ style.svgStyle()->strokePaintColor(), style.svgStyle()->visitedLinkStrokePaintColor(),
+ style.svgStyle()->strokePaintUri(), style.svgStyle()->visitedLinkStrokePaintUri());
case CSSPropertyTextDecorationColor:
- return createFromColor(property, style);
+ return AnimatableColor::create(style.textDecorationColor().resolve(style.color()), style.visitedLinkTextDecorationColor().resolve(style.visitedLinkColor()));
case CSSPropertyTextIndent:
return createFromLength(style.textIndent(), style);
case CSSPropertyTextShadow:
@@ -436,14 +458,19 @@ PassRefPtr<AnimatableValue> CSSAnimatableValueFactory::create(CSSPropertyID prop
return createFromFillLayers<CSSPropertyWebkitMaskPositionY>(style.maskLayers(), style);
case CSSPropertyWebkitMaskSize:
return createFromFillLayers<CSSPropertyWebkitMaskSize>(style.maskLayers(), style);
- case CSSPropertyWebkitPerspective:
+ case CSSPropertyPerspective:
return createFromDouble(style.perspective());
+ case CSSPropertyPerspectiveOrigin:
+ ASSERT(RuntimeEnabledFeatures::cssTransformsUnprefixedEnabled());
+ return AnimatableLengthPoint::create(
+ createFromLength(style.perspectiveOriginX(), style),
+ createFromLength(style.perspectiveOriginY(), style));
case CSSPropertyWebkitPerspectiveOriginX:
+ ASSERT(!RuntimeEnabledFeatures::cssTransformsUnprefixedEnabled());
return createFromLength(style.perspectiveOriginX(), style);
case CSSPropertyWebkitPerspectiveOriginY:
+ ASSERT(!RuntimeEnabledFeatures::cssTransformsUnprefixedEnabled());
return createFromLength(style.perspectiveOriginY(), style);
- case CSSPropertyShapeInside:
- return createFromShapeValue(style.shapeInside());
case CSSPropertyShapeOutside:
return createFromShapeValue(style.shapeOutside());
case CSSPropertyShapeMargin:
@@ -452,13 +479,22 @@ PassRefPtr<AnimatableValue> CSSAnimatableValueFactory::create(CSSPropertyID prop
return createFromDouble(style.shapeImageThreshold());
case CSSPropertyWebkitTextStrokeColor:
return createFromColor(property, style);
- case CSSPropertyWebkitTransform:
+ case CSSPropertyTransform:
return AnimatableTransform::create(style.transform());
+ case CSSPropertyTransformOrigin:
+ ASSERT(RuntimeEnabledFeatures::cssTransformsUnprefixedEnabled());
+ return AnimatableLengthPoint3D::create(
+ createFromLength(style.transformOriginX(), style),
+ createFromLength(style.transformOriginY(), style),
+ createFromDouble(style.transformOriginZ()));
case CSSPropertyWebkitTransformOriginX:
+ ASSERT(!RuntimeEnabledFeatures::cssTransformsUnprefixedEnabled());
return createFromLength(style.transformOriginX(), style);
case CSSPropertyWebkitTransformOriginY:
+ ASSERT(!RuntimeEnabledFeatures::cssTransformsUnprefixedEnabled());
return createFromLength(style.transformOriginY(), style);
case CSSPropertyWebkitTransformOriginZ:
+ ASSERT(!RuntimeEnabledFeatures::cssTransformsUnprefixedEnabled());
return createFromDouble(style.transformOriginZ());
case CSSPropertyWidows:
return createFromDouble(style.widows());
@@ -466,6 +502,10 @@ PassRefPtr<AnimatableValue> CSSAnimatableValueFactory::create(CSSPropertyID prop
return createFromLength(style.width(), style);
case CSSPropertyWordSpacing:
return createFromDouble(style.wordSpacing());
+ case CSSPropertyVerticalAlign:
+ if (style.verticalAlign() == LENGTH)
+ return createFromLength(style.verticalAlignLength(), style);
+ return AnimatableUnknown::create(CSSPrimitiveValue::create(style.verticalAlign()));
case CSSPropertyVisibility:
return AnimatableVisibility::create(style.visibility());
case CSSPropertyZIndex:
@@ -473,10 +513,9 @@ PassRefPtr<AnimatableValue> CSSAnimatableValueFactory::create(CSSPropertyID prop
case CSSPropertyZoom:
return createFromDouble(style.zoom());
default:
- ASSERT_WITH_MESSAGE(!CSSAnimations::isAnimatableProperty(property), "Web Animations not yet implemented: Create AnimatableValue from render style: %s", getPropertyNameString(property).utf8().data());
ASSERT_NOT_REACHED();
// This return value is to avoid a release crash if possible.
- return AnimatableUnknown::create(0);
+ return AnimatableUnknown::create(nullptr);
}
}
diff --git a/chromium/third_party/WebKit/Source/core/animation/css/CSSAnimatableValueFactory.h b/chromium/third_party/WebKit/Source/core/animation/css/CSSAnimatableValueFactory.h
index bac18c19241..7e6ea3dc03d 100644
--- a/chromium/third_party/WebKit/Source/core/animation/css/CSSAnimatableValueFactory.h
+++ b/chromium/third_party/WebKit/Source/core/animation/css/CSSAnimatableValueFactory.h
@@ -31,7 +31,7 @@
#ifndef CSSAnimatableValueFactory_h
#define CSSAnimatableValueFactory_h
-#include "CSSPropertyNames.h"
+#include "core/CSSPropertyNames.h"
#include "core/animation/AnimatableValue.h"
#include "wtf/PassRefPtr.h"
@@ -41,9 +41,9 @@ class RenderStyle;
class CSSAnimatableValueFactory {
public:
- static PassRefPtr<AnimatableValue> create(CSSPropertyID, const RenderStyle&);
+ static PassRefPtrWillBeRawPtr<AnimatableValue> create(CSSPropertyID, const RenderStyle&);
private:
- static PassRefPtr<AnimatableValue> createFromColor(CSSPropertyID, const RenderStyle&);
+ static PassRefPtrWillBeRawPtr<AnimatableValue> createFromColor(CSSPropertyID, const RenderStyle&);
};
} // namespace WebCore
diff --git a/chromium/third_party/WebKit/Source/core/animation/css/CSSAnimationData.cpp b/chromium/third_party/WebKit/Source/core/animation/css/CSSAnimationData.cpp
new file mode 100644
index 00000000000..bda53a4f535
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/css/CSSAnimationData.cpp
@@ -0,0 +1,54 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "config.h"
+#include "core/animation/css/CSSAnimationData.h"
+
+#include "core/animation/Timing.h"
+
+namespace WebCore {
+
+CSSAnimationData::CSSAnimationData()
+{
+ m_nameList.append(initialName());
+ m_iterationCountList.append(initialIterationCount());
+ m_directionList.append(initialDirection());
+ m_fillModeList.append(initialFillMode());
+ m_playStateList.append(initialPlayState());
+}
+
+CSSAnimationData::CSSAnimationData(const CSSAnimationData& other)
+ : CSSTimingData(other)
+ , m_nameList(other.m_nameList)
+ , m_iterationCountList(other.m_iterationCountList)
+ , m_directionList(other.m_directionList)
+ , m_fillModeList(other.m_fillModeList)
+ , m_playStateList(other.m_playStateList)
+{
+}
+
+const AtomicString& CSSAnimationData::initialName()
+{
+ DEFINE_STATIC_LOCAL(const AtomicString, name, ("none", AtomicString::ConstructFromLiteral));
+ return name;
+}
+
+bool CSSAnimationData::animationsMatchForStyleRecalc(const CSSAnimationData& other) const
+{
+ return m_nameList == other.m_nameList && m_playStateList == other.m_playStateList;
+}
+
+Timing CSSAnimationData::convertToTiming(size_t index) const
+{
+ ASSERT(index < m_nameList.size());
+ Timing timing = CSSTimingData::convertToTiming(index);
+
+ timing.iterationCount = getRepeated(m_iterationCountList, index);
+ timing.direction = getRepeated(m_directionList, index);
+ timing.fillMode = getRepeated(m_fillModeList, index);
+ timing.assertValid();
+ return timing;
+}
+
+} // namespace WebCore
diff --git a/chromium/third_party/WebKit/Source/core/animation/css/CSSAnimationData.h b/chromium/third_party/WebKit/Source/core/animation/css/CSSAnimationData.h
new file mode 100644
index 00000000000..5a23feedcc4
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/css/CSSAnimationData.h
@@ -0,0 +1,61 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CSSAnimationData_h
+#define CSSAnimationData_h
+
+#include "core/animation/Timing.h"
+#include "core/animation/css/CSSTimingData.h"
+#include "core/rendering/style/RenderStyleConstants.h"
+
+namespace WebCore {
+
+class CSSAnimationData FINAL : public CSSTimingData {
+public:
+ static PassOwnPtrWillBeRawPtr<CSSAnimationData> create()
+ {
+ return adoptPtrWillBeNoop(new CSSAnimationData);
+ }
+
+ static PassOwnPtrWillBeRawPtr<CSSAnimationData> create(const CSSAnimationData& animationData)
+ {
+ return adoptPtrWillBeNoop(new CSSAnimationData(animationData));
+ }
+
+ bool animationsMatchForStyleRecalc(const CSSAnimationData& other) const;
+
+ Timing convertToTiming(size_t index) const;
+
+ const Vector<AtomicString>& nameList() const { return m_nameList; }
+ const Vector<double>& iterationCountList() const { return m_iterationCountList; }
+ const Vector<Timing::PlaybackDirection>& directionList() const { return m_directionList; }
+ const Vector<Timing::FillMode>& fillModeList() const { return m_fillModeList; }
+ const Vector<EAnimPlayState>& playStateList() const { return m_playStateList; }
+
+ Vector<AtomicString>& nameList() { return m_nameList; }
+ Vector<double>& iterationCountList() { return m_iterationCountList; }
+ Vector<Timing::PlaybackDirection>& directionList() { return m_directionList; }
+ Vector<Timing::FillMode>& fillModeList() { return m_fillModeList; }
+ Vector<EAnimPlayState>& playStateList() { return m_playStateList; }
+
+ static const AtomicString& initialName();
+ static Timing::PlaybackDirection initialDirection() { return Timing::PlaybackDirectionNormal; }
+ static Timing::FillMode initialFillMode() { return Timing::FillModeNone; }
+ static double initialIterationCount() { return 1.0; }
+ static EAnimPlayState initialPlayState() { return AnimPlayStatePlaying; }
+
+private:
+ CSSAnimationData();
+ explicit CSSAnimationData(const CSSAnimationData&);
+
+ Vector<AtomicString> m_nameList;
+ Vector<double> m_iterationCountList;
+ Vector<Timing::PlaybackDirection> m_directionList;
+ Vector<Timing::FillMode> m_fillModeList;
+ Vector<EAnimPlayState> m_playStateList;
+};
+
+} // namespace WebCore
+
+#endif // CSSAnimationData_h
diff --git a/chromium/third_party/WebKit/Source/core/animation/css/CSSAnimations.cpp b/chromium/third_party/WebKit/Source/core/animation/css/CSSAnimations.cpp
index 807c59096b5..05e358ec619 100644
--- a/chromium/third_party/WebKit/Source/core/animation/css/CSSAnimations.cpp
+++ b/chromium/third_party/WebKit/Source/core/animation/css/CSSAnimations.cpp
@@ -31,25 +31,26 @@
#include "config.h"
#include "core/animation/css/CSSAnimations.h"
-#include "StylePropertyShorthand.h"
+#include "core/StylePropertyShorthand.h"
#include "core/animation/ActiveAnimations.h"
+#include "core/animation/AnimationTimeline.h"
#include "core/animation/CompositorAnimations.h"
-#include "core/animation/DocumentTimeline.h"
-#include "core/animation/KeyframeAnimationEffect.h"
+#include "core/animation/KeyframeEffectModel.h"
#include "core/animation/css/CSSAnimatableValueFactory.h"
+#include "core/animation/css/CSSPropertyEquality.h"
+#include "core/animation/interpolation/LegacyStyleInterpolation.h"
#include "core/css/CSSKeyframeRule.h"
+#include "core/css/resolver/CSSToStyleMap.h"
#include "core/css/resolver/StyleResolver.h"
#include "core/dom/Element.h"
#include "core/dom/PseudoElement.h"
-#include "core/events/ThreadLocalEventNames.h"
#include "core/events/TransitionEvent.h"
#include "core/events/WebKitAnimationEvent.h"
#include "core/frame/UseCounter.h"
-#include "core/frame/animation/CSSPropertyAnimation.h"
-#include "core/platform/animation/CSSAnimationDataList.h"
-#include "core/platform/animation/TimingFunction.h"
+#include "core/rendering/RenderLayer.h"
#include "core/rendering/RenderObject.h"
#include "core/rendering/style/KeyframeList.h"
+#include "platform/animation/TimingFunction.h"
#include "public/platform/Platform.h"
#include "wtf/BitArray.h"
#include "wtf/HashSet.h"
@@ -58,90 +59,81 @@ namespace WebCore {
namespace {
-bool isEarlierPhase(TimedItem::Phase target, TimedItem::Phase reference)
+CSSPropertyID propertyForAnimation(CSSPropertyID property)
{
- ASSERT(target != TimedItem::PhaseNone);
- ASSERT(reference != TimedItem::PhaseNone);
- return target < reference;
-}
-
-bool isLaterPhase(TimedItem::Phase target, TimedItem::Phase reference)
-{
- ASSERT(target != TimedItem::PhaseNone);
- ASSERT(reference != TimedItem::PhaseNone);
- return target > reference;
-}
-
-static PassRefPtr<TimingFunction> generateTimingFunction(const KeyframeAnimationEffect::KeyframeVector keyframes, const HashMap<double, RefPtr<TimingFunction> > perKeyframeTimingFunctions)
-{
- // Generate the chained timing function. Note that timing functions apply
- // from the keyframe in which they're specified to the next keyframe.
- bool isTimingFunctionLinearThroughout = true;
- RefPtr<ChainedTimingFunction> chainedTimingFunction = ChainedTimingFunction::create();
- for (size_t i = 0; i < keyframes.size() - 1; ++i) {
- double lowerBound = keyframes[i]->offset();
- ASSERT(lowerBound >=0 && lowerBound < 1);
- double upperBound = keyframes[i + 1]->offset();
- ASSERT(upperBound > 0 && upperBound <= 1);
- TimingFunction* timingFunction = perKeyframeTimingFunctions.get(lowerBound);
- isTimingFunctionLinearThroughout &= timingFunction->type() == TimingFunction::LinearFunction;
- chainedTimingFunction->appendSegment(upperBound, timingFunction);
- }
- if (isTimingFunctionLinearThroughout)
- return LinearTimingFunction::create();
- return chainedTimingFunction;
+ switch (property) {
+ case CSSPropertyWebkitPerspective:
+ return CSSPropertyPerspective;
+ case CSSPropertyWebkitTransform:
+ return CSSPropertyTransform;
+ case CSSPropertyWebkitPerspectiveOriginX:
+ case CSSPropertyWebkitPerspectiveOriginY:
+ if (RuntimeEnabledFeatures::cssTransformsUnprefixedEnabled())
+ return CSSPropertyPerspectiveOrigin;
+ break;
+ case CSSPropertyWebkitTransformOriginX:
+ case CSSPropertyWebkitTransformOriginY:
+ case CSSPropertyWebkitTransformOriginZ:
+ if (RuntimeEnabledFeatures::cssTransformsUnprefixedEnabled())
+ return CSSPropertyTransformOrigin;
+ break;
+ default:
+ break;
+ }
+ return property;
}
static void resolveKeyframes(StyleResolver* resolver, Element* element, const Element& parentElement, const RenderStyle& style, RenderStyle* parentStyle, const AtomicString& name, TimingFunction* defaultTimingFunction,
- Vector<std::pair<KeyframeAnimationEffect::KeyframeVector, RefPtr<TimingFunction> > >& keyframesAndTimingFunctions)
+ AnimatableValueKeyframeVector& keyframes)
{
- ASSERT(RuntimeEnabledFeatures::webAnimationsCSSEnabled());
// When the element is null, use its parent for scoping purposes.
const Element* elementForScoping = element ? element : &parentElement;
const StyleRuleKeyframes* keyframesRule = CSSAnimations::matchScopedKeyframesRule(resolver, elementForScoping, name.impl());
if (!keyframesRule)
return;
- const Vector<RefPtr<StyleKeyframe> >& styleKeyframes = keyframesRule->keyframes();
+ const WillBeHeapVector<RefPtrWillBeMember<StyleKeyframe> >& styleKeyframes = keyframesRule->keyframes();
if (styleKeyframes.isEmpty())
return;
// Construct and populate the style for each keyframe
- PropertySet specifiedProperties;
- KeyframeAnimationEffect::KeyframeVector keyframes;
- HashMap<double, RefPtr<TimingFunction> > perKeyframeTimingFunctions;
+ PropertySet specifiedPropertiesForUseCounter;
for (size_t i = 0; i < styleKeyframes.size(); ++i) {
const StyleKeyframe* styleKeyframe = styleKeyframes[i].get();
// It's OK to pass a null element here.
RefPtr<RenderStyle> keyframeStyle = resolver->styleForKeyframe(element, style, parentStyle, styleKeyframe, name);
- RefPtr<Keyframe> keyframe = Keyframe::create();
+ RefPtrWillBeRawPtr<AnimatableValueKeyframe> keyframe = AnimatableValueKeyframe::create();
const Vector<double>& offsets = styleKeyframe->keys();
ASSERT(!offsets.isEmpty());
keyframe->setOffset(offsets[0]);
- TimingFunction* timingFunction = defaultTimingFunction;
- const StylePropertySet* properties = styleKeyframe->properties();
- for (unsigned j = 0; j < properties->propertyCount(); j++) {
- CSSPropertyID property = properties->propertyAt(j).id();
- specifiedProperties.add(property);
- if (property == CSSPropertyWebkitAnimationTimingFunction || property == CSSPropertyAnimationTimingFunction)
- timingFunction = KeyframeValue::timingFunction(*keyframeStyle);
- else if (CSSAnimations::isAnimatableProperty(property))
+ keyframe->setEasing(defaultTimingFunction);
+ const StylePropertySet& properties = styleKeyframe->properties();
+ for (unsigned j = 0; j < properties.propertyCount(); j++) {
+ specifiedPropertiesForUseCounter.add(properties.propertyAt(j).id());
+ CSSPropertyID property = propertyForAnimation(properties.propertyAt(j).id());
+ if (property == CSSPropertyWebkitAnimationTimingFunction || property == CSSPropertyAnimationTimingFunction) {
+ CSSValue* value = properties.propertyAt(j).value();
+ RefPtr<TimingFunction> timingFunction;
+ if (value->isInheritedValue() && parentStyle->animations())
+ timingFunction = parentStyle->animations()->timingFunctionList()[0];
+ else if (value->isInheritedValue() || value->isInitialValue())
+ timingFunction = CSSTimingData::initialTimingFunction();
+ else
+ timingFunction = CSSToStyleMap::mapAnimationTimingFunction(toCSSValueList(value)->item(0));
+ keyframe->setEasing(timingFunction.release());
+ } else if (CSSAnimations::isAnimatableProperty(property)) {
keyframe->setPropertyValue(property, CSSAnimatableValueFactory::create(property, *keyframeStyle).get());
+ }
}
keyframes.append(keyframe);
// The last keyframe specified at a given offset is used.
- perKeyframeTimingFunctions.set(offsets[0], timingFunction);
for (size_t j = 1; j < offsets.size(); ++j) {
- keyframes.append(keyframe->cloneWithOffset(offsets[j]));
- perKeyframeTimingFunctions.set(offsets[j], timingFunction);
+ keyframes.append(toAnimatableValueKeyframe(keyframe->cloneWithOffset(offsets[j]).get()));
}
}
ASSERT(!keyframes.isEmpty());
- if (!perKeyframeTimingFunctions.contains(0))
- perKeyframeTimingFunctions.set(0, defaultTimingFunction);
-
- for (PropertySet::const_iterator iter = specifiedProperties.begin(); iter != specifiedProperties.end(); ++iter) {
+ for (PropertySet::const_iterator iter = specifiedPropertiesForUseCounter.begin(); iter != specifiedPropertiesForUseCounter.end(); ++iter) {
const CSSPropertyID property = *iter;
ASSERT(property != CSSPropertyInvalid);
blink::Platform::current()->histogramSparse("WebCore.Animation.CSSProperties", UseCounter::mapCSSPropertyIdToCSSSampleIdForHistogram(property));
@@ -159,16 +151,18 @@ static void resolveKeyframes(StyleResolver* resolver, Element* element, const El
keyframes.shrink(targetIndex + 1);
// Add 0% and 100% keyframes if absent.
- RefPtr<Keyframe> startKeyframe = keyframes[0];
+ RefPtrWillBeRawPtr<AnimatableValueKeyframe> startKeyframe = keyframes[0];
if (startKeyframe->offset()) {
- startKeyframe = Keyframe::create();
+ startKeyframe = AnimatableValueKeyframe::create();
startKeyframe->setOffset(0);
+ startKeyframe->setEasing(defaultTimingFunction);
keyframes.prepend(startKeyframe);
}
- RefPtr<Keyframe> endKeyframe = keyframes[keyframes.size() - 1];
+ RefPtrWillBeRawPtr<AnimatableValueKeyframe> endKeyframe = keyframes[keyframes.size() - 1];
if (endKeyframe->offset() != 1) {
- endKeyframe = Keyframe::create();
+ endKeyframe = AnimatableValueKeyframe::create();
endKeyframe->setOffset(1);
+ endKeyframe->setEasing(defaultTimingFunction);
keyframes.append(endKeyframe);
}
ASSERT(keyframes.size() >= 2);
@@ -194,7 +188,7 @@ static void resolveKeyframes(StyleResolver* resolver, Element* element, const El
bool endNeedsValue = missingEndValues && !endKeyframeProperties.contains(property);
if (!startNeedsValue && !endNeedsValue)
continue;
- RefPtr<AnimatableValue> snapshotValue = CSSAnimatableValueFactory::create(property, style);
+ RefPtrWillBeRawPtr<AnimatableValue> snapshotValue = CSSAnimatableValueFactory::create(property, style);
if (startNeedsValue)
startKeyframe->setPropertyValue(property, snapshotValue.get());
if (endNeedsValue)
@@ -203,129 +197,6 @@ static void resolveKeyframes(StyleResolver* resolver, Element* element, const El
}
ASSERT(startKeyframe->properties().size() == allProperties.size());
ASSERT(endKeyframe->properties().size() == allProperties.size());
-
- // Determine how many keyframes specify each property. Note that this must
- // be done after we've filled in end keyframes.
- typedef HashCountedSet<CSSPropertyID> PropertyCountedSet;
- PropertyCountedSet propertyCounts;
- for (size_t i = 0; i < numKeyframes; ++i) {
- const PropertySet& properties = keyframes[i]->properties();
- for (PropertySet::const_iterator iter = properties.begin(); iter != properties.end(); ++iter)
- propertyCounts.add(*iter);
- }
-
- // Split keyframes into groups, where each group contains only keyframes
- // which specify all properties used in that group. Each group is animated
- // in a separate animation, to allow per-keyframe timing functions to be
- // applied correctly.
- for (PropertyCountedSet::const_iterator iter = propertyCounts.begin(); iter != propertyCounts.end(); ++iter) {
- const CSSPropertyID property = iter->key;
- const size_t count = iter->value;
- ASSERT(count <= numKeyframes);
- if (count == numKeyframes)
- continue;
- KeyframeAnimationEffect::KeyframeVector splitOutKeyframes;
- for (size_t i = 0; i < numKeyframes; i++) {
- Keyframe* keyframe = keyframes[i].get();
- if (!keyframe->properties().contains(property)) {
- ASSERT(i && i != numKeyframes - 1);
- continue;
- }
- RefPtr<Keyframe> clonedKeyframe = Keyframe::create();
- clonedKeyframe->setOffset(keyframe->offset());
- clonedKeyframe->setComposite(keyframe->composite());
- clonedKeyframe->setPropertyValue(property, keyframe->propertyValue(property));
- splitOutKeyframes.append(clonedKeyframe);
- // Note that it's OK if this keyframe ends up having no
- // properties. This can only happen when none of the properties
- // are specified in all keyframes, in which case we won't animate
- // anything with these keyframes.
- keyframe->clearPropertyValue(property);
- }
- ASSERT(!splitOutKeyframes.first()->offset());
- ASSERT(splitOutKeyframes.last()->offset() == 1);
-#ifndef NDEBUG
- for (size_t j = 0; j < splitOutKeyframes.size(); ++j)
- ASSERT(splitOutKeyframes[j]->properties().size() == 1);
-#endif
- keyframesAndTimingFunctions.append(std::make_pair(splitOutKeyframes, generateTimingFunction(splitOutKeyframes, perKeyframeTimingFunctions)));
- }
-
- unsigned numPropertiesSpecifiedInAllKeyframes = keyframes.first()->properties().size();
-#ifndef NDEBUG
- for (size_t i = 1; i < numKeyframes; ++i)
- ASSERT(keyframes[i]->properties().size() == numPropertiesSpecifiedInAllKeyframes);
-#endif
-
- // If the animation specifies any keyframes, we always provide at least one
- // vector of resolved keyframes, even if no properties are animated.
- if (numPropertiesSpecifiedInAllKeyframes || keyframesAndTimingFunctions.isEmpty())
- keyframesAndTimingFunctions.append(std::make_pair(keyframes, generateTimingFunction(keyframes, perKeyframeTimingFunctions)));
-}
-
-// Returns the default timing function.
-const PassRefPtr<TimingFunction> timingFromAnimationData(const CSSAnimationData* animationData, Timing& timing, bool& isPaused)
-{
- if (animationData->isDelaySet())
- timing.startDelay = animationData->delay();
- if (animationData->isDurationSet()) {
- timing.iterationDuration = animationData->duration();
- timing.hasIterationDuration = true;
- }
- if (animationData->isIterationCountSet()) {
- if (animationData->iterationCount() == CSSAnimationData::IterationCountInfinite)
- timing.iterationCount = std::numeric_limits<double>::infinity();
- else
- timing.iterationCount = animationData->iterationCount();
- }
- if (animationData->isFillModeSet()) {
- switch (animationData->fillMode()) {
- case AnimationFillModeForwards:
- timing.fillMode = Timing::FillModeForwards;
- break;
- case AnimationFillModeBackwards:
- timing.fillMode = Timing::FillModeBackwards;
- break;
- case AnimationFillModeBoth:
- timing.fillMode = Timing::FillModeBoth;
- break;
- case AnimationFillModeNone:
- timing.fillMode = Timing::FillModeNone;
- break;
- default:
- ASSERT_NOT_REACHED();
- }
- } else {
- timing.fillMode = Timing::FillModeNone;
- }
- if (animationData->isDirectionSet()) {
- switch (animationData->direction()) {
- case CSSAnimationData::AnimationDirectionNormal:
- timing.direction = Timing::PlaybackDirectionNormal;
- break;
- case CSSAnimationData::AnimationDirectionAlternate:
- timing.direction = Timing::PlaybackDirectionAlternate;
- break;
- case CSSAnimationData::AnimationDirectionReverse:
- timing.direction = Timing::PlaybackDirectionReverse;
- break;
- case CSSAnimationData::AnimationDirectionAlternateReverse:
- timing.direction = Timing::PlaybackDirectionAlternateReverse;
- break;
- default:
- ASSERT_NOT_REACHED();
- }
- }
-
- // For CSS, the constraints on the timing properties are tighter than in
- // the general case of the Web Animations model.
- timing.assertValid();
- ASSERT(!timing.iterationStart);
- ASSERT(timing.playbackRate == 1);
- ASSERT(timing.iterationDuration >= 0 && std::isfinite(timing.iterationDuration));
-
- isPaused = animationData->isPlayStateSet() && animationData->playState() == AnimPlayStatePaused;
- return animationData->isTimingFunctionSet() ? animationData->timingFunction() : CSSAnimationData::initialAnimationTimingFunction();
}
} // namespace
@@ -347,21 +218,32 @@ const StyleRuleKeyframes* CSSAnimations::matchScopedKeyframesRule(StyleResolver*
return 0;
}
-PassOwnPtr<CSSAnimationUpdate> CSSAnimations::calculateUpdate(Element* element, const Element& parentElement, const RenderStyle& style, RenderStyle* parentStyle, StyleResolver* resolver)
+CSSAnimations::CSSAnimations()
{
- ASSERT(RuntimeEnabledFeatures::webAnimationsCSSEnabled());
- OwnPtr<CSSAnimationUpdate> update = adoptPtr(new CSSAnimationUpdate());
+}
+
+PassOwnPtrWillBeRawPtr<CSSAnimationUpdate> CSSAnimations::calculateUpdate(Element* element, const Element& parentElement, const RenderStyle& style, RenderStyle* parentStyle, StyleResolver* resolver)
+{
+ OwnPtrWillBeRawPtr<CSSAnimationUpdate> update = adoptPtrWillBeNoop(new CSSAnimationUpdate());
calculateAnimationUpdate(update.get(), element, parentElement, style, parentStyle, resolver);
- calculateAnimationCompositableValues(update.get(), element);
+ calculateAnimationActiveInterpolations(update.get(), element, parentElement.document().timeline().currentTimeInternal());
calculateTransitionUpdate(update.get(), element, style);
- calculateTransitionCompositableValues(update.get(), element);
+ calculateTransitionActiveInterpolations(update.get(), element, parentElement.document().timeline().currentTimeInternal());
return update->isEmpty() ? nullptr : update.release();
}
void CSSAnimations::calculateAnimationUpdate(CSSAnimationUpdate* update, Element* element, const Element& parentElement, const RenderStyle& style, RenderStyle* parentStyle, StyleResolver* resolver)
{
const ActiveAnimations* activeAnimations = element ? element->activeAnimations() : 0;
- const CSSAnimationDataList* animationDataList = style.animations();
+
+#if !ASSERT_ENABLED
+ // If we're in an animation style change, no animations can have started, been cancelled or changed play state.
+ // When ASSERT is enabled, we verify this optimization.
+ if (activeAnimations && activeAnimations->isAnimationStyleChange())
+ return;
+#endif
+
+ const CSSAnimationData* animationData = style.animations();
const CSSAnimations* cssAnimations = activeAnimations ? &activeAnimations->cssAnimations() : 0;
HashSet<AtomicString> inactive;
@@ -370,12 +252,12 @@ void CSSAnimations::calculateAnimationUpdate(CSSAnimationUpdate* update, Element
inactive.add(iter->key);
if (style.display() != NONE) {
- for (size_t i = 0; animationDataList && i < animationDataList->size(); ++i) {
- const CSSAnimationData* animationData = animationDataList->animation(i);
- if (animationData->isNoneAnimation())
+ for (size_t i = 0; animationData && i < animationData->nameList().size(); ++i) {
+ AtomicString animationName(animationData->nameList()[i]);
+ if (animationName == CSSAnimationData::initialName())
continue;
- ASSERT(animationData->isValidAnimation());
- AtomicString animationName(animationData->name());
+
+ bool isPaused = CSSTimingData::getRepeated(animationData->playStateList(), i) == AnimPlayStatePaused;
// Keyframes and animation properties are snapshotted when the
// animation starts, so we don't need to track changes to these,
@@ -384,85 +266,76 @@ void CSSAnimations::calculateAnimationUpdate(CSSAnimationUpdate* update, Element
AnimationMap::const_iterator existing(cssAnimations->m_animations.find(animationName));
if (existing != cssAnimations->m_animations.end()) {
inactive.remove(animationName);
- const HashSet<RefPtr<Player> >& players = existing->value;
- ASSERT(!players.isEmpty());
- bool isFirstPlayerPaused = (*players.begin())->paused();
-#ifndef NDEBUG
- for (HashSet<RefPtr<Player> >::const_iterator iter = players.begin(); iter != players.end(); ++iter)
- ASSERT((*iter)->paused() == isFirstPlayerPaused);
-#endif
- if ((animationData->playState() == AnimPlayStatePaused) != isFirstPlayerPaused)
+ AnimationPlayer* player = existing->value.get();
+ if (isPaused != player->paused()) {
+ ASSERT(!activeAnimations || !activeAnimations->isAnimationStyleChange());
update->toggleAnimationPaused(animationName);
+ }
continue;
}
}
- Timing timing;
- bool isPaused;
- RefPtr<TimingFunction> defaultTimingFunction = timingFromAnimationData(animationData, timing, isPaused);
- Vector<std::pair<KeyframeAnimationEffect::KeyframeVector, RefPtr<TimingFunction> > > keyframesAndTimingFunctions;
- resolveKeyframes(resolver, element, parentElement, style, parentStyle, animationName, defaultTimingFunction.get(), keyframesAndTimingFunctions);
- if (!keyframesAndTimingFunctions.isEmpty()) {
- HashSet<RefPtr<InertAnimation> > animations;
- for (size_t j = 0; j < keyframesAndTimingFunctions.size(); ++j) {
- ASSERT(!keyframesAndTimingFunctions[j].first.isEmpty());
- timing.timingFunction = keyframesAndTimingFunctions[j].second;
- // FIXME: crbug.com/268791 - Keyframes are already normalized, perhaps there should be a flag on KeyframeAnimationEffect to skip normalization.
- animations.add(InertAnimation::create(KeyframeAnimationEffect::create(keyframesAndTimingFunctions[j].first), timing, isPaused));
- }
- update->startAnimation(animationName, animations);
+ Timing timing = animationData->convertToTiming(i);
+ RefPtr<TimingFunction> keyframeTimingFunction = timing.timingFunction;
+ timing.timingFunction = Timing::defaults().timingFunction;
+ AnimatableValueKeyframeVector resolvedKeyframes;
+ resolveKeyframes(resolver, element, parentElement, style, parentStyle, animationName, keyframeTimingFunction.get(), resolvedKeyframes);
+ if (!resolvedKeyframes.isEmpty()) {
+ ASSERT(!activeAnimations || !activeAnimations->isAnimationStyleChange());
+ update->startAnimation(animationName, InertAnimation::create(AnimatableValueKeyframeEffectModel::create(resolvedKeyframes), timing, isPaused));
}
}
}
ASSERT(inactive.isEmpty() || cssAnimations);
- for (HashSet<AtomicString>::const_iterator iter = inactive.begin(); iter != inactive.end(); ++iter)
- update->cancelAnimation(*iter, cssAnimations->m_animations.get(*iter));
+ for (HashSet<AtomicString>::const_iterator iter = inactive.begin(); iter != inactive.end(); ++iter) {
+ ASSERT(!activeAnimations || !activeAnimations->isAnimationStyleChange());
+ update->cancelAnimation(*iter, *cssAnimations->m_animations.get(*iter));
+ }
}
void CSSAnimations::maybeApplyPendingUpdate(Element* element)
{
if (!m_pendingUpdate) {
- m_previousCompositableValuesForAnimations.clear();
+ m_previousActiveInterpolationsForAnimations.clear();
return;
}
- OwnPtr<CSSAnimationUpdate> update = m_pendingUpdate.release();
+ OwnPtrWillBeRawPtr<CSSAnimationUpdate> update = m_pendingUpdate.release();
+
+ m_previousActiveInterpolationsForAnimations.swap(update->activeInterpolationsForAnimations());
- m_previousCompositableValuesForAnimations.swap(update->compositableValuesForAnimations());
+ // FIXME: cancelling, pausing, unpausing animations all query compositingState, which is not necessarily up to date here
+ // since we call this from recalc style.
+ // https://code.google.com/p/chromium/issues/detail?id=339847
+ DisableCompositingQueryAsserts disabler;
for (Vector<AtomicString>::const_iterator iter = update->cancelledAnimationNames().begin(); iter != update->cancelledAnimationNames().end(); ++iter) {
- const HashSet<RefPtr<Player> >& players = m_animations.take(*iter);
- for (HashSet<RefPtr<Player> >::const_iterator iter = players.begin(); iter != players.end(); ++iter)
- (*iter)->cancel();
+ RefPtr<AnimationPlayer> player = m_animations.take(*iter);
+ player->cancel();
+ player->update(TimingUpdateOnDemand);
}
for (Vector<AtomicString>::const_iterator iter = update->animationsWithPauseToggled().begin(); iter != update->animationsWithPauseToggled().end(); ++iter) {
- const HashSet<RefPtr<Player> >& players = m_animations.get(*iter);
- ASSERT(!players.isEmpty());
- bool isFirstPlayerPaused = (*players.begin())->paused();
- for (HashSet<RefPtr<Player> >::const_iterator iter = players.begin(); iter != players.end(); ++iter) {
- Player* player = iter->get();
- ASSERT(player->paused() == isFirstPlayerPaused);
- player->setPaused(!isFirstPlayerPaused);
- }
+ AnimationPlayer* player = m_animations.get(*iter);
+ if (player->paused())
+ player->unpause();
+ else
+ player->pause();
+ if (player->outdated())
+ player->update(TimingUpdateOnDemand);
}
- for (Vector<CSSAnimationUpdate::NewAnimation>::const_iterator iter = update->newAnimations().begin(); iter != update->newAnimations().end(); ++iter) {
+ for (WillBeHeapVector<CSSAnimationUpdate::NewAnimation>::const_iterator iter = update->newAnimations().begin(); iter != update->newAnimations().end(); ++iter) {
+ const InertAnimation* inertAnimation = iter->animation.get();
OwnPtr<AnimationEventDelegate> eventDelegate = adoptPtr(new AnimationEventDelegate(element, iter->name));
- HashSet<RefPtr<Player> > players;
- for (HashSet<RefPtr<InertAnimation> >::const_iterator animationsIter = iter->animations.begin(); animationsIter != iter->animations.end(); ++animationsIter) {
- const InertAnimation* inertAnimation = animationsIter->get();
- // The event delegate is set on the the first animation only. We
- // rely on the behavior of OwnPtr::release() to achieve this.
- RefPtr<Animation> animation = Animation::create(element, inertAnimation->effect(), inertAnimation->specified(), Animation::DefaultPriority, eventDelegate.release());
- Player* player = element->document().timeline()->createPlayer(animation.get());
- player->setPaused(inertAnimation->paused());
- element->document().cssPendingAnimations().add(player);
- player->update();
- players.add(player);
- }
- m_animations.set(iter->name, players);
+ RefPtrWillBeRawPtr<Animation> animation = Animation::create(element, inertAnimation->effect(), inertAnimation->specifiedTiming(), Animation::DefaultPriority, eventDelegate.release());
+ RefPtrWillBeRawPtr<AnimationPlayer> player = element->document().timeline().createAnimationPlayer(animation.get());
+ element->document().compositorPendingAnimations().add(player.get());
+ if (inertAnimation->paused())
+ player->pause();
+ player->update(TimingUpdateOnDemand);
+ m_animations.set(iter->name, player.get());
}
// Transitions that are run on the compositor only update main-thread state
@@ -470,15 +343,17 @@ void CSSAnimations::maybeApplyPendingUpdate(Element* element)
// be when transitions are retargeted. Instead of triggering complete style
// recalculation, we find these cases by searching for new transitions that
// have matching cancelled animation property IDs on the compositor.
- HashMap<CSSPropertyID, std::pair<RefPtr<Animation>, double> > retargetedCompositorTransitions;
- const ActiveAnimations* activeAnimations = element->activeAnimations();
+ WillBeHeapHashMap<CSSPropertyID, std::pair<RefPtrWillBeMember<Animation>, double> > retargetedCompositorTransitions;
for (HashSet<CSSPropertyID>::iterator iter = update->cancelledTransitions().begin(); iter != update->cancelledTransitions().end(); ++iter) {
CSSPropertyID id = *iter;
ASSERT(m_transitions.contains(id));
- Player* player = m_transitions.take(id).transition->player();
- if (activeAnimations && activeAnimations->hasActiveAnimationsOnCompositor(id) && update->newTransitions().find(id) != update->newTransitions().end())
- retargetedCompositorTransitions.add(id, std::pair<RefPtr<Animation>, double>(toAnimation(player->source()), player->startTime()));
+
+ RefPtrWillBeRawPtr<AnimationPlayer> player = m_transitions.take(id).player;
+ Animation* animation = toAnimation(player->source());
+ if (animation->hasActiveAnimationsOnCompositor(id) && update->newTransitions().find(id) != update->newTransitions().end())
+ retargetedCompositorTransitions.add(id, std::pair<RefPtrWillBeMember<Animation>, double>(animation, player->startTimeInternal()));
player->cancel();
+ player->update(TimingUpdateOnDemand);
}
for (CSSAnimationUpdate::NewTransitionMap::const_iterator iter = update->newTransitions().begin(); iter != update->newTransitions().end(); ++iter) {
@@ -490,42 +365,46 @@ void CSSAnimations::maybeApplyPendingUpdate(Element* element)
CSSPropertyID id = newTransition.id;
InertAnimation* inertAnimation = newTransition.animation.get();
- OwnPtr<TransitionEventDelegate> eventDelegate = adoptPtr(new TransitionEventDelegate(element, id));
+ OwnPtr<TransitionEventDelegate> eventDelegate = adoptPtr(new TransitionEventDelegate(element, newTransition.eventId));
- RefPtr<AnimationEffect> effect = inertAnimation->effect();
+ RefPtrWillBeRawPtr<AnimationEffect> effect = inertAnimation->effect();
if (retargetedCompositorTransitions.contains(id)) {
- const std::pair<RefPtr<Animation>, double>& oldTransition = retargetedCompositorTransitions.get(id);
- RefPtr<Animation> oldAnimation = oldTransition.first;
+ const std::pair<RefPtrWillBeMember<Animation>, double>& oldTransition = retargetedCompositorTransitions.get(id);
+ RefPtrWillBeRawPtr<Animation> oldAnimation = oldTransition.first;
double oldStartTime = oldTransition.second;
- double inheritedTime = isNull(oldStartTime) ? 0 : element->document().transitionTimeline()->currentTime() - oldStartTime;
- oldAnimation->updateInheritedTime(inheritedTime);
- KeyframeAnimationEffect* oldEffect = toKeyframeAnimationEffect(inertAnimation->effect());
- const KeyframeAnimationEffect::KeyframeVector& frames = oldEffect->getFrames();
- KeyframeAnimationEffect::KeyframeVector newFrames;
- newFrames.append(frames[0]->clone());
+ double inheritedTime = isNull(oldStartTime) ? 0 : element->document().timeline().currentTimeInternal() - oldStartTime;
+
+ AnimatableValueKeyframeEffectModel* oldEffect = toAnimatableValueKeyframeEffectModel(inertAnimation->effect());
+ const KeyframeVector& frames = oldEffect->getFrames();
+
+ AnimatableValueKeyframeVector newFrames;
+ newFrames.append(toAnimatableValueKeyframe(frames[0]->clone().get()));
+ newFrames.append(toAnimatableValueKeyframe(frames[1]->clone().get()));
+
newFrames[0]->clearPropertyValue(id);
- ASSERT(oldAnimation->compositableValues()->size() == 1);
- const AnimationEffect::CompositableValue* compositableValue = oldAnimation->compositableValues()->at(0).second.get();
- ASSERT(!compositableValue->dependsOnUnderlyingValue());
- newFrames[0]->setPropertyValue(id, compositableValue->compositeOnto(0).get());
- newFrames.append(frames[1]->clone());
- effect = KeyframeAnimationEffect::create(newFrames);
+ RefPtrWillBeRawPtr<InertAnimation> inertAnimationForSampling = InertAnimation::create(oldAnimation->effect(), oldAnimation->specifiedTiming(), false);
+ OwnPtrWillBeRawPtr<WillBeHeapVector<RefPtrWillBeMember<Interpolation> > > sample = inertAnimationForSampling->sample(inheritedTime);
+ ASSERT(sample->size() == 1);
+ newFrames[0]->setPropertyValue(id, toLegacyStyleInterpolation(sample->at(0).get())->currentValue());
+
+ effect = AnimatableValueKeyframeEffectModel::create(newFrames);
}
- RefPtr<Animation> transition = Animation::create(element, effect, inertAnimation->specified(), Animation::TransitionPriority, eventDelegate.release());
- RefPtr<Player> player = element->document().transitionTimeline()->createPlayer(transition.get());
- player->update();
- element->document().cssPendingAnimations().add(player.get());
- runningTransition.transition = transition.get();
+
+ RefPtrWillBeRawPtr<Animation> transition = Animation::create(element, effect, inertAnimation->specifiedTiming(), Animation::TransitionPriority, eventDelegate.release());
+ RefPtrWillBeRawPtr<AnimationPlayer> player = element->document().timeline().createAnimationPlayer(transition.get());
+ element->document().compositorPendingAnimations().add(player.get());
+ player->update(TimingUpdateOnDemand);
+ runningTransition.player = player;
m_transitions.set(id, runningTransition);
ASSERT(id != CSSPropertyInvalid);
blink::Platform::current()->histogramSparse("WebCore.Animation.CSSProperties", UseCounter::mapCSSPropertyIdToCSSSampleIdForHistogram(id));
}
}
-void CSSAnimations::calculateTransitionUpdateForProperty(CSSPropertyID id, const CSSAnimationData* anim, const RenderStyle& oldStyle, const RenderStyle& style, const TransitionMap* activeTransitions, CSSAnimationUpdate* update, const Element* element)
+void CSSAnimations::calculateTransitionUpdateForProperty(CSSPropertyID id, CSSPropertyID eventId, const CSSTransitionData& transitionData, size_t transitionIndex, const RenderStyle& oldStyle, const RenderStyle& style, const TransitionMap* activeTransitions, CSSAnimationUpdate* update, const Element* element)
{
- RefPtr<AnimatableValue> to;
+ RefPtrWillBeRawPtr<AnimatableValue> to = nullptr;
if (activeTransitions) {
TransitionMap::const_iterator activeTransitionIter = activeTransitions->find(id);
if (activeTransitionIter != activeTransitions->end()) {
@@ -538,44 +417,37 @@ void CSSAnimations::calculateTransitionUpdateForProperty(CSSPropertyID id, const
}
}
- if (anim->duration() + anim->delay() <= 0)
+ if (CSSPropertyEquality::propertiesEqual(id, oldStyle, style))
return;
-
- if (CSSPropertyAnimation::propertiesEqual(id, &oldStyle, &style))
- return;
-
if (!to)
to = CSSAnimatableValueFactory::create(id, style);
- RefPtr<AnimatableValue> from = CSSAnimatableValueFactory::create(id, oldStyle);
+ RefPtrWillBeRawPtr<AnimatableValue> from = CSSAnimatableValueFactory::create(id, oldStyle);
// If we have multiple transitions on the same property, we will use the
// last one since we iterate over them in order.
- if (!from->usesNonDefaultInterpolationWith(to.get()))
+ if (AnimatableValue::usesDefaultInterpolation(to.get(), from.get()))
+ return;
+
+ Timing timing = transitionData.convertToTiming(transitionIndex);
+ if (timing.startDelay + timing.iterationDuration <= 0)
return;
- KeyframeAnimationEffect::KeyframeVector keyframes;
+ AnimatableValueKeyframeVector keyframes;
- RefPtr<Keyframe> startKeyframe = Keyframe::create();
+ RefPtrWillBeRawPtr<AnimatableValueKeyframe> startKeyframe = AnimatableValueKeyframe::create();
startKeyframe->setPropertyValue(id, from.get());
startKeyframe->setOffset(0);
+ startKeyframe->setEasing(timing.timingFunction.release());
+ timing.timingFunction = LinearTimingFunction::shared();
keyframes.append(startKeyframe);
- RefPtr<Keyframe> endKeyframe = Keyframe::create();
+ RefPtrWillBeRawPtr<AnimatableValueKeyframe> endKeyframe = AnimatableValueKeyframe::create();
endKeyframe->setPropertyValue(id, to.get());
endKeyframe->setOffset(1);
keyframes.append(endKeyframe);
- RefPtr<KeyframeAnimationEffect> effect = KeyframeAnimationEffect::create(keyframes);
-
- Timing timing;
- bool isPaused;
- RefPtr<TimingFunction> timingFunction = timingFromAnimationData(anim, timing, isPaused);
- ASSERT(!isPaused);
- timing.timingFunction = timingFunction;
- // Note that the backwards part is required for delay to work.
- timing.fillMode = Timing::FillModeBoth;
-
- update->startTransition(id, from.get(), to.get(), InertAnimation::create(effect, timing, isPaused));
+ RefPtrWillBeRawPtr<AnimatableValueKeyframeEffectModel> effect = AnimatableValueKeyframeEffectModel::create(keyframes);
+ update->startTransition(id, eventId, from.get(), to.get(), InertAnimation::create(effect, timing, false));
ASSERT(!element->activeAnimations() || !element->activeAnimations()->isAnimationStyleChange());
}
@@ -586,37 +458,41 @@ void CSSAnimations::calculateTransitionUpdate(CSSAnimationUpdate* update, const
ActiveAnimations* activeAnimations = element->activeAnimations();
const TransitionMap* activeTransitions = activeAnimations ? &activeAnimations->cssAnimations().m_transitions : 0;
+ const CSSTransitionData* transitionData = style.transitions();
-#if ASSERT_DISABLED
- // In release builds we avoid the cost of checking for new and interrupted transitions if the style recalc is due to animation.
- const bool animationStyleRecalc = activeAnimations && activeAnimations->isAnimationStyleChange();
-#else
+#if ASSERT_ENABLED
// In debug builds we verify that it would have been safe to avoid populating and testing listedProperties if the style recalc is due to animation.
const bool animationStyleRecalc = false;
+#else
+ // In release builds we avoid the cost of checking for new and interrupted transitions if the style recalc is due to animation.
+ const bool animationStyleRecalc = activeAnimations && activeAnimations->isAnimationStyleChange();
#endif
BitArray<numCSSProperties> listedProperties;
- bool anyTransitionHadAnimateAll = false;
+ bool anyTransitionHadTransitionAll = false;
const RenderObject* renderer = element->renderer();
- if (!animationStyleRecalc && style.display() != NONE && renderer && renderer->style() && style.transitions()) {
+ if (!animationStyleRecalc && style.display() != NONE && renderer && renderer->style() && transitionData) {
const RenderStyle& oldStyle = *renderer->style();
- for (size_t i = 0; i < style.transitions()->size(); ++i) {
- const CSSAnimationData* anim = style.transitions()->animation(i);
- CSSAnimationData::AnimationMode mode = anim->animationMode();
- if (mode == CSSAnimationData::AnimateNone)
+ for (size_t i = 0; i < transitionData->propertyList().size(); ++i) {
+ const CSSTransitionData::TransitionProperty& transitionProperty = transitionData->propertyList()[i];
+ CSSTransitionData::TransitionPropertyType mode = transitionProperty.propertyType;
+ CSSPropertyID property = transitionProperty.propertyId;
+ if (mode == CSSTransitionData::TransitionNone || mode == CSSTransitionData::TransitionUnknown)
continue;
- bool animateAll = mode == CSSAnimationData::AnimateAll;
- ASSERT(animateAll || mode == CSSAnimationData::AnimateSingleProperty);
+ bool animateAll = mode == CSSTransitionData::TransitionAll;
+ ASSERT(animateAll || mode == CSSTransitionData::TransitionSingleProperty);
if (animateAll)
- anyTransitionHadAnimateAll = true;
- const StylePropertyShorthand& propertyList = animateAll ? CSSAnimations::animatableProperties() : shorthandForProperty(anim->property());
+ anyTransitionHadTransitionAll = true;
+ const StylePropertyShorthand& propertyList = animateAll ? CSSAnimations::animatableProperties() : shorthandForProperty(property);
// If not a shorthand we only execute one iteration of this loop, and refer to the property directly.
for (unsigned j = 0; !j || j < propertyList.length(); ++j) {
- CSSPropertyID id = propertyList.length() ? propertyList.properties()[j] : anim->property();
+ CSSPropertyID id = propertyList.length() ? propertyList.properties()[j] : property;
+ CSSPropertyID eventId = id;
if (!animateAll) {
+ id = propertyForAnimation(id);
if (CSSAnimations::isAnimatableProperty(id))
listedProperties.set(id);
else
@@ -625,9 +501,9 @@ void CSSAnimations::calculateTransitionUpdate(CSSAnimationUpdate* update, const
// FIXME: We should transition if an !important property changes even when an animation is running,
// but this is a bit hard to do with the current applyMatchedProperties system.
- if (!update->compositableValuesForAnimations().contains(id)
- && (!activeAnimations || !activeAnimations->cssAnimations().m_previousCompositableValuesForAnimations.contains(id))) {
- calculateTransitionUpdateForProperty(id, anim, oldStyle, style, activeTransitions, update, element);
+ if (!update->activeInterpolationsForAnimations().contains(id)
+ && (!activeAnimations || !activeAnimations->cssAnimations().m_previousActiveInterpolationsForAnimations.contains(id))) {
+ calculateTransitionUpdateForProperty(id, eventId, *transitionData, i, oldStyle, style, activeTransitions, update, element);
}
}
}
@@ -635,10 +511,11 @@ void CSSAnimations::calculateTransitionUpdate(CSSAnimationUpdate* update, const
if (activeTransitions) {
for (TransitionMap::const_iterator iter = activeTransitions->begin(); iter != activeTransitions->end(); ++iter) {
- const TimedItem* timedItem = iter->value.transition;
+ const AnimationPlayer& player = *iter->value.player;
CSSPropertyID id = iter->key;
- if (timedItem->phase() == TimedItem::PhaseAfter || (!anyTransitionHadAnimateAll && !animationStyleRecalc && !listedProperties.get(id))) {
- ASSERT(timedItem->phase() == TimedItem::PhaseAfter || !(activeAnimations && activeAnimations->isAnimationStyleChange()));
+ if (player.finishedInternal() || (!anyTransitionHadTransitionAll && !animationStyleRecalc && !listedProperties.get(id))) {
+ // TODO: Figure out why this fails on Chrome OS login page. crbug.com/365507
+ // ASSERT(player.finishedInternal() || !(activeAnimations && activeAnimations->isAnimationStyleChange()));
update->cancelTransition(id);
}
}
@@ -648,130 +525,129 @@ void CSSAnimations::calculateTransitionUpdate(CSSAnimationUpdate* update, const
void CSSAnimations::cancel()
{
for (AnimationMap::iterator iter = m_animations.begin(); iter != m_animations.end(); ++iter) {
- const HashSet<RefPtr<Player> >& players = iter->value;
- for (HashSet<RefPtr<Player> >::const_iterator animationsIter = players.begin(); animationsIter != players.end(); ++animationsIter)
- (*animationsIter)->cancel();
+ iter->value->cancel();
+ iter->value->update(TimingUpdateOnDemand);
}
- for (TransitionMap::iterator iter = m_transitions.begin(); iter != m_transitions.end(); ++iter)
- iter->value.transition->player()->cancel();
+ for (TransitionMap::iterator iter = m_transitions.begin(); iter != m_transitions.end(); ++iter) {
+ iter->value.player->cancel();
+ iter->value.player->update(TimingUpdateOnDemand);
+ }
m_animations.clear();
m_transitions.clear();
m_pendingUpdate = nullptr;
}
-void CSSAnimations::calculateAnimationCompositableValues(CSSAnimationUpdate* update, const Element* element)
+void CSSAnimations::calculateAnimationActiveInterpolations(CSSAnimationUpdate* update, const Element* element, double timelineCurrentTime)
{
ActiveAnimations* activeAnimations = element ? element->activeAnimations() : 0;
AnimationStack* animationStack = activeAnimations ? &activeAnimations->defaultStack() : 0;
- if (update->newAnimations().isEmpty() && update->cancelledAnimationPlayers().isEmpty()) {
- AnimationEffect::CompositableValueMap compositableValuesForAnimations(AnimationStack::compositableValues(animationStack, 0, 0, Animation::DefaultPriority));
- update->adoptCompositableValuesForAnimations(compositableValuesForAnimations);
+ if (update->newAnimations().isEmpty() && update->cancelledAnimationAnimationPlayers().isEmpty()) {
+ WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> > activeInterpolationsForAnimations(AnimationStack::activeInterpolations(animationStack, 0, 0, Animation::DefaultPriority, timelineCurrentTime));
+ update->adoptActiveInterpolationsForAnimations(activeInterpolationsForAnimations);
return;
}
- Vector<InertAnimation*> newAnimations;
+ WillBeHeapVector<RawPtrWillBeMember<InertAnimation> > newAnimations;
for (size_t i = 0; i < update->newAnimations().size(); ++i) {
- HashSet<RefPtr<InertAnimation> > animations = update->newAnimations()[i].animations;
- for (HashSet<RefPtr<InertAnimation> >::const_iterator animationsIter = animations.begin(); animationsIter != animations.end(); ++animationsIter)
- newAnimations.append(animationsIter->get());
+ newAnimations.append(update->newAnimations()[i].animation.get());
}
- AnimationEffect::CompositableValueMap compositableValuesForAnimations(AnimationStack::compositableValues(animationStack, &newAnimations, &update->cancelledAnimationPlayers(), Animation::DefaultPriority));
- update->adoptCompositableValuesForAnimations(compositableValuesForAnimations);
+ WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> > activeInterpolationsForAnimations(AnimationStack::activeInterpolations(animationStack, &newAnimations, &update->cancelledAnimationAnimationPlayers(), Animation::DefaultPriority, timelineCurrentTime));
+ update->adoptActiveInterpolationsForAnimations(activeInterpolationsForAnimations);
}
-void CSSAnimations::calculateTransitionCompositableValues(CSSAnimationUpdate* update, const Element* element)
+void CSSAnimations::calculateTransitionActiveInterpolations(CSSAnimationUpdate* update, const Element* element, double timelineCurrentTime)
{
ActiveAnimations* activeAnimations = element ? element->activeAnimations() : 0;
AnimationStack* animationStack = activeAnimations ? &activeAnimations->defaultStack() : 0;
- AnimationEffect::CompositableValueMap compositableValuesForTransitions;
+ WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> > activeInterpolationsForTransitions;
if (update->newTransitions().isEmpty() && update->cancelledTransitions().isEmpty()) {
- compositableValuesForTransitions = AnimationStack::compositableValues(animationStack, 0, 0, Animation::TransitionPriority);
+ activeInterpolationsForTransitions = AnimationStack::activeInterpolations(animationStack, 0, 0, Animation::TransitionPriority, timelineCurrentTime);
} else {
- Vector<InertAnimation*> newTransitions;
+ WillBeHeapVector<RawPtrWillBeMember<InertAnimation> > newTransitions;
for (CSSAnimationUpdate::NewTransitionMap::const_iterator iter = update->newTransitions().begin(); iter != update->newTransitions().end(); ++iter)
newTransitions.append(iter->value.animation.get());
- HashSet<const Player*> cancelledPlayers;
+ WillBeHeapHashSet<RawPtrWillBeMember<const AnimationPlayer> > cancelledAnimationPlayers;
if (!update->cancelledTransitions().isEmpty()) {
ASSERT(activeAnimations);
const TransitionMap& transitionMap = activeAnimations->cssAnimations().m_transitions;
for (HashSet<CSSPropertyID>::iterator iter = update->cancelledTransitions().begin(); iter != update->cancelledTransitions().end(); ++iter) {
ASSERT(transitionMap.contains(*iter));
- cancelledPlayers.add(transitionMap.get(*iter).transition->player());
+ cancelledAnimationPlayers.add(transitionMap.get(*iter).player.get());
}
}
- compositableValuesForTransitions = AnimationStack::compositableValues(animationStack, &newTransitions, &cancelledPlayers, Animation::TransitionPriority);
+ activeInterpolationsForTransitions = AnimationStack::activeInterpolations(animationStack, &newTransitions, &cancelledAnimationPlayers, Animation::TransitionPriority, timelineCurrentTime);
}
// Properties being animated by animations don't get values from transitions applied.
- if (!update->compositableValuesForAnimations().isEmpty() && !compositableValuesForTransitions.isEmpty()) {
- for (AnimationEffect::CompositableValueMap::const_iterator iter = update->compositableValuesForAnimations().begin(); iter != update->compositableValuesForAnimations().end(); ++iter)
- compositableValuesForTransitions.remove(iter->key);
+ if (!update->activeInterpolationsForAnimations().isEmpty() && !activeInterpolationsForTransitions.isEmpty()) {
+ for (WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> >::const_iterator iter = update->activeInterpolationsForAnimations().begin(); iter != update->activeInterpolationsForAnimations().end(); ++iter)
+ activeInterpolationsForTransitions.remove(iter->key);
}
- update->adoptCompositableValuesForTransitions(compositableValuesForTransitions);
+ update->adoptActiveInterpolationsForTransitions(activeInterpolationsForTransitions);
}
void CSSAnimations::AnimationEventDelegate::maybeDispatch(Document::ListenerType listenerType, const AtomicString& eventName, double elapsedTime)
{
- if (m_target->document().hasListenerType(listenerType))
- m_target->document().timeline()->addEventToDispatch(m_target, WebKitAnimationEvent::create(eventName, m_name, elapsedTime));
+ if (m_target->document().hasListenerType(listenerType)) {
+ RefPtrWillBeRawPtr<WebKitAnimationEvent> event = WebKitAnimationEvent::create(eventName, m_name, elapsedTime);
+ event->setTarget(m_target);
+ m_target->document().enqueueAnimationFrameEvent(event);
+ }
}
-void CSSAnimations::AnimationEventDelegate::onEventCondition(const TimedItem* timedItem, bool isFirstSample, TimedItem::Phase previousPhase, double previousIteration)
+void CSSAnimations::AnimationEventDelegate::onEventCondition(const AnimationNode* animationNode)
{
- // Events for a single document are queued and dispatched as a group at
- // the end of DocumentTimeline::serviceAnimations.
- // FIXME: Events which are queued outside of serviceAnimations should
- // trigger a timer to dispatch when control is released.
- const TimedItem::Phase currentPhase = timedItem->phase();
- const double currentIteration = timedItem->currentIteration();
-
- // Note that the elapsedTime is measured from when the animation starts playing.
- if (!isFirstSample && previousPhase == TimedItem::PhaseActive && currentPhase == TimedItem::PhaseActive && previousIteration != currentIteration) {
- ASSERT(!isNull(previousIteration));
- ASSERT(!isNull(currentIteration));
+ const AnimationNode::Phase currentPhase = animationNode->phase();
+ const double currentIteration = animationNode->currentIteration();
+
+ if (m_previousPhase != currentPhase
+ && (currentPhase == AnimationNode::PhaseActive || currentPhase == AnimationNode::PhaseAfter)
+ && (m_previousPhase == AnimationNode::PhaseNone || m_previousPhase == AnimationNode::PhaseBefore)) {
+ // The spec states that the elapsed time should be
+ // 'delay < 0 ? -delay : 0', but we always use 0 to match the existing
+ // implementation. See crbug.com/279611
+ maybeDispatch(Document::ANIMATIONSTART_LISTENER, EventTypeNames::animationstart, 0);
+ }
+
+ if (currentPhase == AnimationNode::PhaseActive && m_previousPhase == currentPhase && m_previousIteration != currentIteration) {
// We fire only a single event for all iterations thast terminate
// between a single pair of samples. See http://crbug.com/275263. For
// compatibility with the existing implementation, this event uses
// the elapsedTime for the first iteration in question.
- ASSERT(timedItem->specified().hasIterationDuration);
- const double elapsedTime = timedItem->specified().iterationDuration * (previousIteration + 1);
+ ASSERT(!std::isnan(animationNode->specifiedTiming().iterationDuration));
+ const double elapsedTime = animationNode->specifiedTiming().iterationDuration * (m_previousIteration + 1);
maybeDispatch(Document::ANIMATIONITERATION_LISTENER, EventTypeNames::animationiteration, elapsedTime);
- return;
}
- if ((isFirstSample || previousPhase == TimedItem::PhaseBefore) && isLaterPhase(currentPhase, TimedItem::PhaseBefore)) {
- ASSERT(timedItem->specified().startDelay > 0 || isFirstSample);
- // The spec states that the elapsed time should be
- // 'delay < 0 ? -delay : 0', but we always use 0 to match the existing
- // implementation. See crbug.com/279611
- maybeDispatch(Document::ANIMATIONSTART_LISTENER, EventTypeNames::animationstart, 0);
- }
- if ((isFirstSample || isEarlierPhase(previousPhase, TimedItem::PhaseAfter)) && currentPhase == TimedItem::PhaseAfter)
- maybeDispatch(Document::ANIMATIONEND_LISTENER, EventTypeNames::animationend, timedItem->activeDuration());
+
+ if (currentPhase == AnimationNode::PhaseAfter && m_previousPhase != AnimationNode::PhaseAfter)
+ maybeDispatch(Document::ANIMATIONEND_LISTENER, EventTypeNames::animationend, animationNode->activeDurationInternal());
+
+ m_previousPhase = currentPhase;
+ m_previousIteration = currentIteration;
}
-void CSSAnimations::TransitionEventDelegate::onEventCondition(const TimedItem* timedItem, bool isFirstSample, TimedItem::Phase previousPhase, double previousIteration)
+void CSSAnimations::TransitionEventDelegate::onEventCondition(const AnimationNode* animationNode)
{
- // Events for a single document are queued and dispatched as a group at
- // the end of DocumentTimeline::serviceAnimations.
- // FIXME: Events which are queued outside of serviceAnimations should
- // trigger a timer to dispatch when control is released.
- const TimedItem::Phase currentPhase = timedItem->phase();
- if (currentPhase == TimedItem::PhaseAfter && (isFirstSample || previousPhase != currentPhase) && m_target->document().hasListenerType(Document::TRANSITIONEND_LISTENER)) {
+ const AnimationNode::Phase currentPhase = animationNode->phase();
+ if (currentPhase == AnimationNode::PhaseAfter && currentPhase != m_previousPhase && m_target->document().hasListenerType(Document::TRANSITIONEND_LISTENER)) {
String propertyName = getPropertyNameString(m_property);
- const Timing& timing = timedItem->specified();
+ const Timing& timing = animationNode->specifiedTiming();
double elapsedTime = timing.iterationDuration;
const AtomicString& eventType = EventTypeNames::transitionend;
String pseudoElement = PseudoElement::pseudoElementNameForEvents(m_target->pseudoId());
- m_target->document().transitionTimeline()->addEventToDispatch(m_target, TransitionEvent::create(eventType, propertyName, elapsedTime, pseudoElement));
+ RefPtrWillBeRawPtr<TransitionEvent> event = TransitionEvent::create(eventType, propertyName, elapsedTime, pseudoElement);
+ event->setTarget(m_target);
+ m_target->document().enqueueAnimationFrameEvent(event);
}
-}
+ m_previousPhase = currentPhase;
+}
bool CSSAnimations::isAnimatableProperty(CSSPropertyID property)
{
@@ -810,8 +686,8 @@ bool CSSAnimations::isAnimatableProperty(CSSPropertyID property)
case CSSPropertyFloodColor:
case CSSPropertyFloodOpacity:
case CSSPropertyFontSize:
+ case CSSPropertyFontWeight:
case CSSPropertyHeight:
- case CSSPropertyKerning:
case CSSPropertyLeft:
case CSSPropertyLetterSpacing:
case CSSPropertyLightingColor:
@@ -848,6 +724,7 @@ bool CSSAnimations::isAnimatableProperty(CSSPropertyID property)
case CSSPropertyTextIndent:
case CSSPropertyTextShadow:
case CSSPropertyTop:
+ case CSSPropertyVerticalAlign:
case CSSPropertyVisibility:
case CSSPropertyWebkitBackgroundSize:
case CSSPropertyWebkitBorderHorizontalSpacing:
@@ -868,29 +745,27 @@ bool CSSAnimations::isAnimatableProperty(CSSPropertyID property)
case CSSPropertyWebkitMaskPositionX:
case CSSPropertyWebkitMaskPositionY:
case CSSPropertyWebkitMaskSize:
- case CSSPropertyWebkitPerspective:
- case CSSPropertyWebkitPerspectiveOriginX:
- case CSSPropertyWebkitPerspectiveOriginY:
- case CSSPropertyShapeInside:
+ case CSSPropertyPerspective:
case CSSPropertyShapeOutside:
case CSSPropertyShapeMargin:
case CSSPropertyShapeImageThreshold:
case CSSPropertyWebkitTextStrokeColor:
- case CSSPropertyWebkitTransform:
- case CSSPropertyWebkitTransformOriginX:
- case CSSPropertyWebkitTransformOriginY:
- case CSSPropertyWebkitTransformOriginZ:
+ case CSSPropertyTransform:
case CSSPropertyWidows:
case CSSPropertyWidth:
case CSSPropertyWordSpacing:
case CSSPropertyZIndex:
case CSSPropertyZoom:
return true;
- // FIXME: Shorthands should not be present in this list, but
- // CSSPropertyAnimation implements animation of these shorthands
- // directly and makes use of this method.
- case CSSPropertyFlex:
- return !RuntimeEnabledFeatures::webAnimationsCSSEnabled();
+ case CSSPropertyPerspectiveOrigin:
+ case CSSPropertyTransformOrigin:
+ return RuntimeEnabledFeatures::cssTransformsUnprefixedEnabled();
+ case CSSPropertyWebkitPerspectiveOriginX:
+ case CSSPropertyWebkitPerspectiveOriginY:
+ case CSSPropertyWebkitTransformOriginX:
+ case CSSPropertyWebkitTransformOriginY:
+ case CSSPropertyWebkitTransformOriginZ:
+ return !RuntimeEnabledFeatures::cssTransformsUnprefixedEnabled();
default:
return false;
}
@@ -911,4 +786,61 @@ const StylePropertyShorthand& CSSAnimations::animatableProperties()
return propertyShorthand;
}
+// Animation properties are not allowed to be affected by Web Animations.
+// http://dev.w3.org/fxtf/web-animations/#not-animatable
+bool CSSAnimations::isAllowedAnimation(CSSPropertyID property)
+{
+ switch (property) {
+ case CSSPropertyAnimation:
+ case CSSPropertyAnimationDelay:
+ case CSSPropertyAnimationDirection:
+ case CSSPropertyAnimationDuration:
+ case CSSPropertyAnimationFillMode:
+ case CSSPropertyAnimationIterationCount:
+ case CSSPropertyAnimationName:
+ case CSSPropertyAnimationPlayState:
+ case CSSPropertyAnimationTimingFunction:
+ case CSSPropertyDisplay:
+ case CSSPropertyTransition:
+ case CSSPropertyTransitionDelay:
+ case CSSPropertyTransitionDuration:
+ case CSSPropertyTransitionProperty:
+ case CSSPropertyTransitionTimingFunction:
+ case CSSPropertyWebkitAnimation:
+ case CSSPropertyWebkitAnimationDelay:
+ case CSSPropertyWebkitAnimationDirection:
+ case CSSPropertyWebkitAnimationDuration:
+ case CSSPropertyWebkitAnimationFillMode:
+ case CSSPropertyWebkitAnimationIterationCount:
+ case CSSPropertyWebkitAnimationName:
+ case CSSPropertyWebkitAnimationPlayState:
+ case CSSPropertyWebkitAnimationTimingFunction:
+ case CSSPropertyWebkitTransition:
+ case CSSPropertyWebkitTransitionDelay:
+ case CSSPropertyWebkitTransitionDuration:
+ case CSSPropertyWebkitTransitionProperty:
+ case CSSPropertyWebkitTransitionTimingFunction:
+ return false;
+ default:
+ return true;
+ }
+}
+
+void CSSAnimations::trace(Visitor* visitor)
+{
+ visitor->trace(m_transitions);
+ visitor->trace(m_pendingUpdate);
+ visitor->trace(m_animations);
+ visitor->trace(m_previousActiveInterpolationsForAnimations);
+}
+
+void CSSAnimationUpdate::trace(Visitor* visitor)
+{
+ visitor->trace(m_newTransitions);
+ visitor->trace(m_activeInterpolationsForAnimations);
+ visitor->trace(m_activeInterpolationsForTransitions);
+ visitor->trace(m_newAnimations);
+ visitor->trace(m_cancelledAnimationPlayers);
+}
+
} // namespace WebCore
diff --git a/chromium/third_party/WebKit/Source/core/animation/css/CSSAnimations.h b/chromium/third_party/WebKit/Source/core/animation/css/CSSAnimations.h
index fb553d96232..31159f908ec 100644
--- a/chromium/third_party/WebKit/Source/core/animation/css/CSSAnimations.h
+++ b/chromium/third_party/WebKit/Source/core/animation/css/CSSAnimations.h
@@ -32,11 +32,11 @@
#define CSSAnimations_h
#include "core/animation/Animation.h"
+#include "core/animation/AnimationPlayer.h"
#include "core/animation/InertAnimation.h"
-#include "core/animation/Player.h"
+#include "core/animation/interpolation/Interpolation.h"
#include "core/css/StylePropertySet.h"
#include "core/dom/Document.h"
-#include "core/platform/animation/CSSAnimationData.h"
#include "core/rendering/style/RenderStyleConstants.h"
#include "wtf/HashMap.h"
#include "wtf/Vector.h"
@@ -44,39 +44,40 @@
namespace WebCore {
+class CSSTransitionData;
class Element;
class StylePropertyShorthand;
class StyleResolver;
class StyleRuleKeyframes;
// This class stores the CSS Animations/Transitions information we use during a style recalc.
-// This includes updates to animations/transitions as well as the CompositableValueMaps to be applied.
-class CSSAnimationUpdate FINAL {
+// This includes updates to animations/transitions as well as the Interpolations to be applied.
+class CSSAnimationUpdate FINAL : public NoBaseWillBeGarbageCollectedFinalized<CSSAnimationUpdate> {
public:
- void startAnimation(AtomicString& animationName, const HashSet<RefPtr<InertAnimation> >& animations)
+ void startAnimation(AtomicString& animationName, PassRefPtrWillBeRawPtr<InertAnimation> animation)
{
NewAnimation newAnimation;
newAnimation.name = animationName;
- newAnimation.animations = animations;
+ newAnimation.animation = animation;
m_newAnimations.append(newAnimation);
}
// Returns whether player has been cancelled and should be filtered during style application.
- bool isCancelledAnimation(const Player* player) const { return m_cancelledAnimationPlayers.contains(player); }
- void cancelAnimation(const AtomicString& name, const HashSet<RefPtr<Player> >& players)
+ bool isCancelledAnimation(const AnimationPlayer* player) const { return m_cancelledAnimationPlayers.contains(player); }
+ void cancelAnimation(const AtomicString& name, AnimationPlayer& player)
{
m_cancelledAnimationNames.append(name);
- for (HashSet<RefPtr<Player> >::const_iterator iter = players.begin(); iter != players.end(); ++iter)
- m_cancelledAnimationPlayers.add(iter->get());
+ m_cancelledAnimationPlayers.add(&player);
}
void toggleAnimationPaused(const AtomicString& name)
{
m_animationsWithPauseToggled.append(name);
}
- void startTransition(CSSPropertyID id, const AnimatableValue* from, const AnimatableValue* to, PassRefPtr<InertAnimation> animation)
+ void startTransition(CSSPropertyID id, CSSPropertyID eventId, const AnimatableValue* from, const AnimatableValue* to, PassRefPtrWillBeRawPtr<InertAnimation> animation)
{
NewTransition newTransition;
newTransition.id = id;
+ newTransition.eventId = eventId;
newTransition.from = from;
newTransition.to = to;
newTransition.animation = animation;
@@ -86,29 +87,46 @@ public:
void cancelTransition(CSSPropertyID id) { m_cancelledTransitions.add(id); }
struct NewAnimation {
+ ALLOW_ONLY_INLINE_ALLOCATION();
+ public:
+ void trace(Visitor* visitor)
+ {
+ visitor->trace(animation);
+ }
+
AtomicString name;
- HashSet<RefPtr<InertAnimation> > animations;
+ RefPtrWillBeMember<InertAnimation> animation;
};
- const Vector<NewAnimation>& newAnimations() const { return m_newAnimations; }
+ const WillBeHeapVector<NewAnimation>& newAnimations() const { return m_newAnimations; }
const Vector<AtomicString>& cancelledAnimationNames() const { return m_cancelledAnimationNames; }
- const HashSet<const Player*>& cancelledAnimationPlayers() const { return m_cancelledAnimationPlayers; }
+ const WillBeHeapHashSet<RawPtrWillBeMember<const AnimationPlayer> >& cancelledAnimationAnimationPlayers() const { return m_cancelledAnimationPlayers; }
const Vector<AtomicString>& animationsWithPauseToggled() const { return m_animationsWithPauseToggled; }
struct NewTransition {
+ ALLOW_ONLY_INLINE_ALLOCATION();
+ public:
+ void trace(Visitor* visitor)
+ {
+ visitor->trace(from);
+ visitor->trace(to);
+ visitor->trace(animation);
+ }
+
CSSPropertyID id;
- const AnimatableValue* from;
- const AnimatableValue* to;
- RefPtr<InertAnimation> animation;
+ CSSPropertyID eventId;
+ RawPtrWillBeMember<const AnimatableValue> from;
+ RawPtrWillBeMember<const AnimatableValue> to;
+ RefPtrWillBeMember<InertAnimation> animation;
};
- typedef HashMap<CSSPropertyID, NewTransition> NewTransitionMap;
+ typedef WillBeHeapHashMap<CSSPropertyID, NewTransition> NewTransitionMap;
const NewTransitionMap& newTransitions() const { return m_newTransitions; }
const HashSet<CSSPropertyID>& cancelledTransitions() const { return m_cancelledTransitions; }
- void adoptCompositableValuesForAnimations(AnimationEffect::CompositableValueMap& newMap) { newMap.swap(m_compositableValuesForAnimations); }
- void adoptCompositableValuesForTransitions(AnimationEffect::CompositableValueMap& newMap) { newMap.swap(m_compositableValuesForTransitions); }
- const AnimationEffect::CompositableValueMap& compositableValuesForAnimations() const { return m_compositableValuesForAnimations; }
- const AnimationEffect::CompositableValueMap& compositableValuesForTransitions() const { return m_compositableValuesForTransitions; }
- AnimationEffect::CompositableValueMap& compositableValuesForAnimations() { return m_compositableValuesForAnimations; }
+ void adoptActiveInterpolationsForAnimations(WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> >& newMap) { newMap.swap(m_activeInterpolationsForAnimations); }
+ void adoptActiveInterpolationsForTransitions(WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> >& newMap) { newMap.swap(m_activeInterpolationsForTransitions); }
+ const WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> >& activeInterpolationsForAnimations() const { return m_activeInterpolationsForAnimations; }
+ const WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> >& activeInterpolationsForTransitions() const { return m_activeInterpolationsForTransitions; }
+ WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> >& activeInterpolationsForAnimations() { return m_activeInterpolationsForAnimations; }
bool isEmpty() const
{
@@ -118,28 +136,35 @@ public:
&& m_animationsWithPauseToggled.isEmpty()
&& m_newTransitions.isEmpty()
&& m_cancelledTransitions.isEmpty()
- && m_compositableValuesForAnimations.isEmpty()
- && m_compositableValuesForTransitions.isEmpty();
+ && m_activeInterpolationsForAnimations.isEmpty()
+ && m_activeInterpolationsForTransitions.isEmpty();
}
+
+ void trace(Visitor*);
+
private:
// Order is significant since it defines the order in which new animations
// will be started. Note that there may be multiple animations present
// with the same name, due to the way in which we split up animations with
// incomplete keyframes.
- Vector<NewAnimation> m_newAnimations;
+ WillBeHeapVector<NewAnimation> m_newAnimations;
Vector<AtomicString> m_cancelledAnimationNames;
- HashSet<const Player*> m_cancelledAnimationPlayers;
+ WillBeHeapHashSet<RawPtrWillBeMember<const AnimationPlayer> > m_cancelledAnimationPlayers;
Vector<AtomicString> m_animationsWithPauseToggled;
NewTransitionMap m_newTransitions;
HashSet<CSSPropertyID> m_cancelledTransitions;
- AnimationEffect::CompositableValueMap m_compositableValuesForAnimations;
- AnimationEffect::CompositableValueMap m_compositableValuesForTransitions;
+ WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> > m_activeInterpolationsForAnimations;
+ WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> > m_activeInterpolationsForTransitions;
};
class CSSAnimations FINAL {
+ WTF_MAKE_NONCOPYABLE(CSSAnimations);
+ DISALLOW_ALLOCATION();
public:
+ CSSAnimations();
+
// FIXME: This method is only used here and in the legacy animations
// implementation. It should be made private or file-scope when the legacy
// engine is removed.
@@ -147,68 +172,91 @@ public:
static bool isAnimatableProperty(CSSPropertyID);
static const StylePropertyShorthand& animatableProperties();
+ static bool isAllowedAnimation(CSSPropertyID);
// FIXME: This should take a const ScopedStyleTree instead of a StyleResolver.
// We should also change the Element* to a const Element*
- static PassOwnPtr<CSSAnimationUpdate> calculateUpdate(Element*, const Element& parentElement, const RenderStyle&, RenderStyle* parentStyle, StyleResolver*);
+ static PassOwnPtrWillBeRawPtr<CSSAnimationUpdate> calculateUpdate(Element*, const Element& parentElement, const RenderStyle&, RenderStyle* parentStyle, StyleResolver*);
- void setPendingUpdate(PassOwnPtr<CSSAnimationUpdate> update) { m_pendingUpdate = update; }
+ void setPendingUpdate(PassOwnPtrWillBeRawPtr<CSSAnimationUpdate> update) { m_pendingUpdate = update; }
void maybeApplyPendingUpdate(Element*);
bool isEmpty() const { return m_animations.isEmpty() && m_transitions.isEmpty() && !m_pendingUpdate; }
void cancel();
+ void trace(Visitor*);
+
private:
- // Note that a single animation name may map to multiple players due to
- // the way in which we split up animations with incomplete keyframes.
- // FIXME: Once the Web Animations model supports groups, we could use a
- // ParGroup to drive multiple animations from a single Player.
- typedef HashMap<AtomicString, HashSet<RefPtr<Player> > > AnimationMap;
struct RunningTransition {
- Animation* transition; // The TransitionTimeline keeps the Players alive
- const AnimatableValue* from;
- const AnimatableValue* to;
+ ALLOW_ONLY_INLINE_ALLOCATION();
+ public:
+ void trace(Visitor* visitor)
+ {
+ visitor->trace(from);
+ visitor->trace(to);
+ visitor->trace(player);
+ }
+
+ RefPtrWillBeMember<AnimationPlayer> player;
+ RawPtrWillBeMember<const AnimatableValue> from;
+ RawPtrWillBeMember<const AnimatableValue> to;
};
- typedef HashMap<CSSPropertyID, RunningTransition > TransitionMap;
+
+ typedef WillBeHeapHashMap<AtomicString, RefPtrWillBeMember<AnimationPlayer> > AnimationMap;
AnimationMap m_animations;
+
+ typedef WillBeHeapHashMap<CSSPropertyID, RunningTransition> TransitionMap;
TransitionMap m_transitions;
- OwnPtr<CSSAnimationUpdate> m_pendingUpdate;
- AnimationEffect::CompositableValueMap m_previousCompositableValuesForAnimations;
+ OwnPtrWillBeMember<CSSAnimationUpdate> m_pendingUpdate;
+
+ WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> > m_previousActiveInterpolationsForAnimations;
static void calculateAnimationUpdate(CSSAnimationUpdate*, Element*, const Element& parentElement, const RenderStyle&, RenderStyle* parentStyle, StyleResolver*);
static void calculateTransitionUpdate(CSSAnimationUpdate*, const Element*, const RenderStyle&);
- static void calculateTransitionUpdateForProperty(CSSPropertyID, const CSSAnimationData*, const RenderStyle& oldStyle, const RenderStyle&, const TransitionMap* activeTransitions, CSSAnimationUpdate*, const Element*);
+ static void calculateTransitionUpdateForProperty(CSSPropertyID, CSSPropertyID eventId, const CSSTransitionData&, size_t transitionIndex, const RenderStyle& oldStyle, const RenderStyle&, const TransitionMap* activeTransitions, CSSAnimationUpdate*, const Element*);
- static void calculateAnimationCompositableValues(CSSAnimationUpdate*, const Element*);
- static void calculateTransitionCompositableValues(CSSAnimationUpdate*, const Element*);
+ static void calculateAnimationActiveInterpolations(CSSAnimationUpdate*, const Element*, double timelineCurrentTime);
+ static void calculateTransitionActiveInterpolations(CSSAnimationUpdate*, const Element*, double timelineCurrentTime);
- class AnimationEventDelegate FINAL : public TimedItem::EventDelegate {
+ class AnimationEventDelegate FINAL : public AnimationNode::EventDelegate {
public:
AnimationEventDelegate(Element* target, const AtomicString& name)
: m_target(target)
, m_name(name)
+ , m_previousPhase(AnimationNode::PhaseNone)
+ , m_previousIteration(nullValue())
{
}
- virtual void onEventCondition(const TimedItem*, bool isFirstSample, TimedItem::Phase previousPhase, double previousIteration) OVERRIDE;
+ virtual void onEventCondition(const AnimationNode*) OVERRIDE;
private:
void maybeDispatch(Document::ListenerType, const AtomicString& eventName, double elapsedTime);
Element* m_target;
const AtomicString m_name;
+ AnimationNode::Phase m_previousPhase;
+ double m_previousIteration;
};
- class TransitionEventDelegate FINAL : public TimedItem::EventDelegate {
+ class TransitionEventDelegate FINAL : public AnimationNode::EventDelegate {
public:
TransitionEventDelegate(Element* target, CSSPropertyID property)
: m_target(target)
, m_property(property)
+ , m_previousPhase(AnimationNode::PhaseNone)
{
}
- virtual void onEventCondition(const TimedItem*, bool isFirstSample, TimedItem::Phase previousPhase, double previousIteration) OVERRIDE;
+ virtual void onEventCondition(const AnimationNode*) OVERRIDE;
private:
Element* m_target;
const CSSPropertyID m_property;
+ AnimationNode::Phase m_previousPhase;
};
};
} // namespace WebCore
+namespace WTF {
+template<> struct VectorTraits<WebCore::CSSAnimationUpdate::NewAnimation> : VectorTraitsBase<WebCore::CSSAnimationUpdate::NewAnimation> {
+ static const bool canInitializeWithMemset = true;
+};
+}
+
#endif
diff --git a/chromium/third_party/WebKit/Source/core/animation/css/CSSPropertyEquality.cpp b/chromium/third_party/WebKit/Source/core/animation/css/CSSPropertyEquality.cpp
new file mode 100644
index 00000000000..70ad01dbcb4
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/css/CSSPropertyEquality.cpp
@@ -0,0 +1,318 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "config.h"
+#include "core/animation/css/CSSPropertyEquality.h"
+
+#include "core/animation/css/CSSAnimations.h"
+#include "core/rendering/style/DataEquivalency.h"
+#include "core/rendering/style/RenderStyle.h"
+#include "core/rendering/style/ShadowList.h"
+
+namespace WebCore {
+
+namespace {
+
+template <CSSPropertyID property>
+bool fillLayersEqual(const FillLayer* aLayer, const FillLayer* bLayer)
+{
+ if (aLayer == bLayer)
+ return true;
+ if (!aLayer || !bLayer)
+ return false;
+ while (aLayer && bLayer) {
+ switch (property) {
+ case CSSPropertyBackgroundPositionX:
+ case CSSPropertyWebkitMaskPositionX:
+ if (aLayer->xPosition() != bLayer->xPosition())
+ return false;
+ break;
+ case CSSPropertyBackgroundPositionY:
+ case CSSPropertyWebkitMaskPositionY:
+ if (aLayer->yPosition() != bLayer->yPosition())
+ return false;
+ break;
+ case CSSPropertyBackgroundSize:
+ case CSSPropertyWebkitBackgroundSize:
+ case CSSPropertyWebkitMaskSize:
+ if (!(aLayer->sizeLength() == bLayer->sizeLength()))
+ return false;
+ break;
+ case CSSPropertyBackgroundImage:
+ if (!dataEquivalent(aLayer->image(), bLayer->image()))
+ return false;
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ return true;
+ }
+
+ aLayer = aLayer->next();
+ bLayer = bLayer->next();
+ }
+
+ // FIXME: Shouldn't this be return !aLayer && !bLayer; ?
+ return true;
+}
+
+}
+
+bool CSSPropertyEquality::propertiesEqual(CSSPropertyID prop, const RenderStyle& a, const RenderStyle& b)
+{
+ switch (prop) {
+ case CSSPropertyBackgroundColor:
+ return a.backgroundColor().resolve(a.color()) == b.backgroundColor().resolve(b.color())
+ && a.visitedLinkBackgroundColor().resolve(a.color()) == b.visitedLinkBackgroundColor().resolve(b.color());
+ case CSSPropertyBackgroundImage:
+ return fillLayersEqual<CSSPropertyBackgroundImage>(a.backgroundLayers(), b.backgroundLayers());
+ case CSSPropertyBackgroundPositionX:
+ return fillLayersEqual<CSSPropertyBackgroundPositionX>(a.backgroundLayers(), b.backgroundLayers());
+ case CSSPropertyBackgroundPositionY:
+ return fillLayersEqual<CSSPropertyBackgroundPositionY>(a.backgroundLayers(), b.backgroundLayers());
+ case CSSPropertyBackgroundSize:
+ return fillLayersEqual<CSSPropertyBackgroundSize>(a.backgroundLayers(), b.backgroundLayers());
+ case CSSPropertyBaselineShift:
+ return dataEquivalent(a.baselineShiftValue(), b.baselineShiftValue());
+ case CSSPropertyBorderBottomColor:
+ return a.borderBottomColor().resolve(a.color()) == b.borderBottomColor().resolve(b.color())
+ && a.visitedLinkBorderBottomColor().resolve(a.color()) == b.visitedLinkBorderBottomColor().resolve(b.color());
+ case CSSPropertyBorderBottomLeftRadius:
+ return a.borderBottomLeftRadius() == b.borderBottomLeftRadius();
+ case CSSPropertyBorderBottomRightRadius:
+ return a.borderBottomRightRadius() == b.borderBottomRightRadius();
+ case CSSPropertyBorderBottomWidth:
+ return a.borderBottomWidth() == b.borderBottomWidth();
+ case CSSPropertyBorderImageOutset:
+ return a.borderImageOutset() == b.borderImageOutset();
+ case CSSPropertyBorderImageSlice:
+ return a.borderImageSlices() == b.borderImageSlices();
+ case CSSPropertyBorderImageSource:
+ return dataEquivalent(a.borderImageSource(), b.borderImageSource());
+ case CSSPropertyBorderImageWidth:
+ return a.borderImageWidth() == b.borderImageWidth();
+ case CSSPropertyBorderLeftColor:
+ return a.borderLeftColor().resolve(a.color()) == b.borderLeftColor().resolve(b.color())
+ && a.visitedLinkBorderLeftColor().resolve(a.color()) == b.visitedLinkBorderLeftColor().resolve(b.color());
+ case CSSPropertyBorderLeftWidth:
+ return a.borderLeftWidth() == b.borderLeftWidth();
+ case CSSPropertyBorderRightColor:
+ return a.borderRightColor().resolve(a.color()) == b.borderRightColor().resolve(b.color())
+ && a.visitedLinkBorderRightColor().resolve(a.color()) == b.visitedLinkBorderRightColor().resolve(b.color());
+ case CSSPropertyBorderRightWidth:
+ return a.borderRightWidth() == b.borderRightWidth();
+ case CSSPropertyBorderTopColor:
+ return a.borderTopColor().resolve(a.color()) == b.borderTopColor().resolve(b.color())
+ && a.visitedLinkBorderTopColor().resolve(a.color()) == b.visitedLinkBorderTopColor().resolve(b.color());
+ case CSSPropertyBorderTopLeftRadius:
+ return a.borderTopLeftRadius() == b.borderTopLeftRadius();
+ case CSSPropertyBorderTopRightRadius:
+ return a.borderTopRightRadius() == b.borderTopRightRadius();
+ case CSSPropertyBorderTopWidth:
+ return a.borderTopWidth() == b.borderTopWidth();
+ case CSSPropertyBottom:
+ return a.bottom() == b.bottom();
+ case CSSPropertyBoxShadow:
+ return dataEquivalent(a.boxShadow(), b.boxShadow());
+ case CSSPropertyClip:
+ return a.clip() == b.clip();
+ case CSSPropertyColor:
+ return a.color() == b.color() && a.visitedLinkColor() == b.visitedLinkColor();
+ case CSSPropertyFill: {
+ const SVGRenderStyle& aSVG = *a.svgStyle();
+ const SVGRenderStyle& bSVG = *b.svgStyle();
+ return aSVG.fillPaintType() == bSVG.fillPaintType()
+ && (aSVG.fillPaintType() != SVGPaint::SVG_PAINTTYPE_RGBCOLOR || aSVG.fillPaintColor() == bSVG.fillPaintColor())
+ && aSVG.visitedLinkFillPaintType() == bSVG.visitedLinkFillPaintType()
+ && (aSVG.visitedLinkFillPaintType() != SVGPaint::SVG_PAINTTYPE_RGBCOLOR || aSVG.visitedLinkFillPaintColor() == bSVG.visitedLinkFillPaintColor());
+ }
+ case CSSPropertyFillOpacity:
+ return a.fillOpacity() == b.fillOpacity();
+ case CSSPropertyFlexBasis:
+ return a.flexBasis() == b.flexBasis();
+ case CSSPropertyFlexGrow:
+ return a.flexGrow() == b.flexGrow();
+ case CSSPropertyFlexShrink:
+ return a.flexShrink() == b.flexShrink();
+ case CSSPropertyFloodColor:
+ return a.floodColor() == b.floodColor();
+ case CSSPropertyFloodOpacity:
+ return a.floodOpacity() == b.floodOpacity();
+ case CSSPropertyFontSize:
+ // CSSPropertyFontSize: Must pass a specified size to setFontSize if Text Autosizing is enabled, but a computed size
+ // if text zoom is enabled (if neither is enabled it's irrelevant as they're probably the same).
+ // FIXME: Should we introduce an option to pass the computed font size here, allowing consumers to
+ // enable text zoom rather than Text Autosizing? See http://crbug.com/227545.
+ return a.specifiedFontSize() == b.specifiedFontSize();
+ case CSSPropertyFontWeight:
+ return a.fontWeight() == b.fontWeight();
+ case CSSPropertyHeight:
+ return a.height() == b.height();
+ case CSSPropertyLeft:
+ return a.left() == b.left();
+ case CSSPropertyLetterSpacing:
+ return a.letterSpacing() == b.letterSpacing();
+ case CSSPropertyLightingColor:
+ return a.lightingColor() == b.lightingColor();
+ case CSSPropertyLineHeight:
+ return a.specifiedLineHeight() == b.specifiedLineHeight();
+ case CSSPropertyListStyleImage:
+ return dataEquivalent(a.listStyleImage(), b.listStyleImage());
+ case CSSPropertyMarginBottom:
+ return a.marginBottom() == b.marginBottom();
+ case CSSPropertyMarginLeft:
+ return a.marginLeft() == b.marginLeft();
+ case CSSPropertyMarginRight:
+ return a.marginRight() == b.marginRight();
+ case CSSPropertyMarginTop:
+ return a.marginTop() == b.marginTop();
+ case CSSPropertyMaxHeight:
+ return a.maxHeight() == b.maxHeight();
+ case CSSPropertyMaxWidth:
+ return a.maxWidth() == b.maxWidth();
+ case CSSPropertyMinHeight:
+ return a.minHeight() == b.minHeight();
+ case CSSPropertyMinWidth:
+ return a.minWidth() == b.minWidth();
+ case CSSPropertyObjectPosition:
+ return a.objectPosition() == b.objectPosition();
+ case CSSPropertyOpacity:
+ return a.opacity() == b.opacity();
+ case CSSPropertyOrphans:
+ return a.orphans() == b.orphans();
+ case CSSPropertyOutlineColor:
+ return a.outlineColor().resolve(a.color()) == b.outlineColor().resolve(b.color())
+ && a.visitedLinkOutlineColor().resolve(a.color()) == b.visitedLinkOutlineColor().resolve(b.color());
+ case CSSPropertyOutlineOffset:
+ return a.outlineOffset() == b.outlineOffset();
+ case CSSPropertyOutlineWidth:
+ return a.outlineWidth() == b.outlineWidth();
+ case CSSPropertyPaddingBottom:
+ return a.paddingBottom() == b.paddingBottom();
+ case CSSPropertyPaddingLeft:
+ return a.paddingLeft() == b.paddingLeft();
+ case CSSPropertyPaddingRight:
+ return a.paddingRight() == b.paddingRight();
+ case CSSPropertyPaddingTop:
+ return a.paddingTop() == b.paddingTop();
+ case CSSPropertyRight:
+ return a.right() == b.right();
+ case CSSPropertyShapeImageThreshold:
+ return a.shapeImageThreshold() == b.shapeImageThreshold();
+ case CSSPropertyShapeMargin:
+ return a.shapeMargin() == b.shapeMargin();
+ case CSSPropertyShapeOutside:
+ return dataEquivalent(a.shapeOutside(), b.shapeOutside());
+ case CSSPropertyStopColor:
+ return a.stopColor() == b.stopColor();
+ case CSSPropertyStopOpacity:
+ return a.stopOpacity() == b.stopOpacity();
+ case CSSPropertyStroke: {
+ const SVGRenderStyle& aSVG = *a.svgStyle();
+ const SVGRenderStyle& bSVG = *b.svgStyle();
+ return aSVG.strokePaintType() == bSVG.strokePaintType()
+ && (aSVG.strokePaintType() != SVGPaint::SVG_PAINTTYPE_RGBCOLOR || aSVG.strokePaintColor() == bSVG.strokePaintColor())
+ && aSVG.visitedLinkStrokePaintType() == bSVG.visitedLinkStrokePaintType()
+ && (aSVG.visitedLinkStrokePaintType() != SVGPaint::SVG_PAINTTYPE_RGBCOLOR || aSVG.visitedLinkStrokePaintColor() == bSVG.visitedLinkStrokePaintColor());
+ }
+ case CSSPropertyStrokeDasharray:
+ return dataEquivalent(a.strokeDashArray(), b.strokeDashArray());
+ case CSSPropertyStrokeDashoffset:
+ return dataEquivalent(a.strokeDashOffset(), b.strokeDashOffset());
+ case CSSPropertyStrokeMiterlimit:
+ return a.strokeMiterLimit() == b.strokeMiterLimit();
+ case CSSPropertyStrokeOpacity:
+ return a.strokeOpacity() == b.strokeOpacity();
+ case CSSPropertyStrokeWidth:
+ return dataEquivalent(a.strokeWidth(), b.strokeWidth());
+ case CSSPropertyTextDecorationColor:
+ return a.textDecorationColor().resolve(a.color()) == b.textDecorationColor().resolve(b.color())
+ && a.visitedLinkTextDecorationColor().resolve(a.color()) == b.visitedLinkTextDecorationColor().resolve(b.color());
+ case CSSPropertyTextIndent:
+ return a.textIndent() == b.textIndent();
+ case CSSPropertyTextShadow:
+ return dataEquivalent(a.textShadow(), b.textShadow());
+ case CSSPropertyTop:
+ return a.top() == b.top();
+ case CSSPropertyVerticalAlign:
+ return a.verticalAlign() == b.verticalAlign()
+ && (a.verticalAlign() != LENGTH || a.verticalAlignLength() == b.verticalAlignLength());
+ case CSSPropertyVisibility:
+ return a.visibility() == b.visibility();
+ case CSSPropertyWebkitBackgroundSize:
+ return fillLayersEqual<CSSPropertyWebkitBackgroundSize>(a.backgroundLayers(), b.backgroundLayers());
+ case CSSPropertyWebkitBorderHorizontalSpacing:
+ return a.horizontalBorderSpacing() == b.horizontalBorderSpacing();
+ case CSSPropertyWebkitBorderVerticalSpacing:
+ return a.verticalBorderSpacing() == b.verticalBorderSpacing();
+ case CSSPropertyWebkitBoxShadow:
+ return dataEquivalent(a.boxShadow(), b.boxShadow());
+ case CSSPropertyWebkitClipPath:
+ return dataEquivalent(a.clipPath(), b.clipPath());
+ case CSSPropertyWebkitColumnCount:
+ return a.columnCount() == b.columnCount();
+ case CSSPropertyWebkitColumnGap:
+ return a.columnGap() == b.columnGap();
+ case CSSPropertyWebkitColumnRuleColor:
+ return a.columnRuleColor().resolve(a.color()) == b.columnRuleColor().resolve(b.color())
+ && a.visitedLinkColumnRuleColor().resolve(a.color()) == b.visitedLinkColumnRuleColor().resolve(b.color());
+ case CSSPropertyWebkitColumnRuleWidth:
+ return a.columnRuleWidth() == b.columnRuleWidth();
+ case CSSPropertyWebkitColumnWidth:
+ return a.columnWidth() == b.columnWidth();
+ case CSSPropertyWebkitFilter:
+ return a.filter() == b.filter();
+ case CSSPropertyWebkitMaskBoxImageOutset:
+ return a.maskBoxImageOutset() == b.maskBoxImageOutset();
+ case CSSPropertyWebkitMaskBoxImageSlice:
+ return a.maskBoxImageSlices() == b.maskBoxImageSlices();
+ case CSSPropertyWebkitMaskBoxImageSource:
+ return dataEquivalent(a.maskBoxImageSource(), b.maskBoxImageSource());
+ case CSSPropertyWebkitMaskBoxImageWidth:
+ return a.maskBoxImageWidth() == b.maskBoxImageWidth();
+ case CSSPropertyWebkitMaskImage:
+ return dataEquivalent(a.maskImage(), b.maskImage());
+ case CSSPropertyWebkitMaskPositionX:
+ return fillLayersEqual<CSSPropertyWebkitMaskPositionX>(a.maskLayers(), b.maskLayers());
+ case CSSPropertyWebkitMaskPositionY:
+ return fillLayersEqual<CSSPropertyWebkitMaskPositionY>(a.maskLayers(), b.maskLayers());
+ case CSSPropertyWebkitMaskSize:
+ return fillLayersEqual<CSSPropertyWebkitMaskSize>(a.maskLayers(), b.maskLayers());
+ case CSSPropertyPerspective:
+ return a.perspective() == b.perspective();
+ case CSSPropertyPerspectiveOrigin:
+ return a.perspectiveOriginX() == b.perspectiveOriginX() && a.perspectiveOriginY() == b.perspectiveOriginY();
+ case CSSPropertyWebkitPerspectiveOriginX:
+ return a.perspectiveOriginX() == b.perspectiveOriginX();
+ case CSSPropertyWebkitPerspectiveOriginY:
+ return a.perspectiveOriginY() == b.perspectiveOriginY();
+ case CSSPropertyWebkitTextStrokeColor:
+ return a.textStrokeColor().resolve(a.color()) == b.textStrokeColor().resolve(b.color())
+ && a.visitedLinkTextStrokeColor().resolve(a.color()) == b.visitedLinkTextStrokeColor().resolve(b.color());
+ case CSSPropertyTransform:
+ return a.transform() == b.transform();
+ case CSSPropertyTransformOrigin:
+ return a.transformOriginX() == b.transformOriginX() && a.transformOriginY() == b.transformOriginY() && a.transformOriginZ() == b.transformOriginZ();
+ case CSSPropertyWebkitTransformOriginX:
+ return a.transformOriginX() == b.transformOriginX();
+ case CSSPropertyWebkitTransformOriginY:
+ return a.transformOriginY() == b.transformOriginY();
+ case CSSPropertyWebkitTransformOriginZ:
+ return a.transformOriginZ() == b.transformOriginZ();
+ case CSSPropertyWidows:
+ return a.widows() == b.widows();
+ case CSSPropertyWidth:
+ return a.width() == b.width();
+ case CSSPropertyWordSpacing:
+ return a.wordSpacing() == b.wordSpacing();
+ case CSSPropertyZIndex:
+ return a.zIndex() == b.zIndex();
+ case CSSPropertyZoom:
+ return a.zoom() == b.zoom();
+ default:
+ ASSERT_NOT_REACHED();
+ return true;
+ }
+}
+
+}
diff --git a/chromium/third_party/WebKit/Source/core/animation/css/CSSPropertyEquality.h b/chromium/third_party/WebKit/Source/core/animation/css/CSSPropertyEquality.h
new file mode 100644
index 00000000000..0a436f0046c
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/css/CSSPropertyEquality.h
@@ -0,0 +1,21 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CSSPropertyEquality_h
+#define CSSPropertyEquality_h
+
+#include "core/CSSPropertyNames.h"
+
+namespace WebCore {
+
+class RenderStyle;
+
+class CSSPropertyEquality {
+public:
+ static bool propertiesEqual(CSSPropertyID, const RenderStyle&, const RenderStyle&);
+};
+
+} // namespace WebCore
+
+#endif // CSSPropertyEquality_h
diff --git a/chromium/third_party/WebKit/Source/core/animation/css/CSSTimingData.cpp b/chromium/third_party/WebKit/Source/core/animation/css/CSSTimingData.cpp
new file mode 100644
index 00000000000..9d628bd32c3
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/css/CSSTimingData.cpp
@@ -0,0 +1,36 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "config.h"
+#include "core/animation/css/CSSTimingData.h"
+
+#include "core/animation/Timing.h"
+
+namespace WebCore {
+
+CSSTimingData::CSSTimingData()
+{
+ m_delayList.append(initialDelay());
+ m_durationList.append(initialDuration());
+ m_timingFunctionList.append(initialTimingFunction());
+}
+
+CSSTimingData::CSSTimingData(const CSSTimingData& other)
+ : m_delayList(other.m_delayList)
+ , m_durationList(other.m_durationList)
+ , m_timingFunctionList(other.m_timingFunctionList)
+{
+}
+
+Timing CSSTimingData::convertToTiming(size_t index) const
+{
+ Timing timing;
+ timing.startDelay = getRepeated(m_delayList, index);
+ timing.iterationDuration = getRepeated(m_durationList, index);
+ timing.timingFunction = getRepeated(m_timingFunctionList, index);
+ timing.assertValid();
+ return timing;
+}
+
+} // namespace WebCore
diff --git a/chromium/third_party/WebKit/Source/core/animation/css/CSSTimingData.h b/chromium/third_party/WebKit/Source/core/animation/css/CSSTimingData.h
new file mode 100644
index 00000000000..33eab3b4b27
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/css/CSSTimingData.h
@@ -0,0 +1,50 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CSSTimingData_h
+#define CSSTimingData_h
+
+#include "platform/animation/TimingFunction.h"
+#include "platform/heap/Handle.h"
+#include "wtf/Vector.h"
+
+namespace WebCore {
+
+struct Timing;
+
+class CSSTimingData : public NoBaseWillBeGarbageCollectedFinalized<CSSTimingData> {
+public:
+ ~CSSTimingData() { }
+
+ void trace(Visitor*) { }
+
+ const Vector<double>& delayList() const { return m_delayList; }
+ const Vector<double>& durationList() const { return m_durationList; }
+ const Vector<RefPtr<TimingFunction> >& timingFunctionList() const { return m_timingFunctionList; }
+
+ Vector<double>& delayList() { return m_delayList; }
+ Vector<double>& durationList() { return m_durationList; }
+ Vector<RefPtr<TimingFunction> >& timingFunctionList() { return m_timingFunctionList; }
+
+ static double initialDelay() { return 0; }
+ static double initialDuration() { return 0; }
+ static PassRefPtr<TimingFunction> initialTimingFunction() { return CubicBezierTimingFunction::preset(CubicBezierTimingFunction::Ease); }
+
+ template <class T> static const T& getRepeated(const Vector<T>& v, size_t index) { return v[index % v.size()]; }
+
+protected:
+ CSSTimingData();
+ explicit CSSTimingData(const CSSTimingData&);
+
+ Timing convertToTiming(size_t index) const;
+
+private:
+ Vector<double> m_delayList;
+ Vector<double> m_durationList;
+ Vector<RefPtr<TimingFunction> > m_timingFunctionList;
+};
+
+} // namespace WebCore
+
+#endif // CSSTimingData_h
diff --git a/chromium/third_party/WebKit/Source/core/animation/css/CSSTransitionData.cpp b/chromium/third_party/WebKit/Source/core/animation/css/CSSTransitionData.cpp
new file mode 100644
index 00000000000..ad20621f30f
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/css/CSSTransitionData.cpp
@@ -0,0 +1,37 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "config.h"
+#include "core/animation/css/CSSTransitionData.h"
+
+#include "core/animation/Timing.h"
+
+namespace WebCore {
+
+CSSTransitionData::CSSTransitionData()
+{
+ m_propertyList.append(initialProperty());
+}
+
+CSSTransitionData::CSSTransitionData(const CSSTransitionData& other)
+ : CSSTimingData(other)
+ , m_propertyList(other.m_propertyList)
+{
+}
+
+bool CSSTransitionData::transitionsMatchForStyleRecalc(const CSSTransitionData& other) const
+{
+ return m_propertyList == other.m_propertyList;
+}
+
+Timing CSSTransitionData::convertToTiming(size_t index) const
+{
+ ASSERT(index < m_propertyList.size());
+ // Note that the backwards fill part is required for delay to work.
+ Timing timing = CSSTimingData::convertToTiming(index);
+ timing.fillMode = Timing::FillModeBoth;
+ return timing;
+}
+
+} // namespace WebCore
diff --git a/chromium/third_party/WebKit/Source/core/animation/css/CSSTransitionData.h b/chromium/third_party/WebKit/Source/core/animation/css/CSSTransitionData.h
new file mode 100644
index 00000000000..792afc77afa
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/css/CSSTransitionData.h
@@ -0,0 +1,81 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CSSTransitionData_h
+#define CSSTransitionData_h
+
+#include "core/CSSPropertyNames.h"
+#include "core/animation/css/CSSTimingData.h"
+#include "wtf/Vector.h"
+
+namespace WebCore {
+
+class CSSTransitionData FINAL : public CSSTimingData {
+public:
+ enum TransitionPropertyType {
+ TransitionNone,
+ TransitionSingleProperty,
+ TransitionUnknown,
+ TransitionAll
+ };
+
+ // FIXME: We shouldn't allow 'none' to be used alongside other properties.
+ struct TransitionProperty {
+ TransitionProperty(CSSPropertyID id)
+ : propertyType(TransitionSingleProperty)
+ , propertyId(id)
+ {
+ ASSERT(id != CSSPropertyInvalid);
+ }
+
+ TransitionProperty(const String& string)
+ : propertyType(TransitionUnknown)
+ , propertyId(CSSPropertyInvalid)
+ , propertyString(string)
+ {
+ }
+
+ TransitionProperty(TransitionPropertyType type)
+ : propertyType(type)
+ , propertyId(CSSPropertyInvalid)
+ {
+ ASSERT(type == TransitionNone || type == TransitionAll);
+ }
+
+ bool operator==(const TransitionProperty& other) const { return propertyType == other.propertyType && propertyId == other.propertyId && propertyString == other.propertyString; }
+
+ TransitionPropertyType propertyType;
+ CSSPropertyID propertyId;
+ String propertyString;
+ };
+
+ static PassOwnPtrWillBeRawPtr<CSSTransitionData> create()
+ {
+ return adoptPtrWillBeNoop(new CSSTransitionData);
+ }
+
+ static PassOwnPtrWillBeRawPtr<CSSTransitionData> create(const CSSTransitionData& transitionData)
+ {
+ return adoptPtrWillBeNoop(new CSSTransitionData(transitionData));
+ }
+
+ bool transitionsMatchForStyleRecalc(const CSSTransitionData& other) const;
+
+ Timing convertToTiming(size_t index) const;
+
+ const Vector<TransitionProperty>& propertyList() const { return m_propertyList; }
+ Vector<TransitionProperty>& propertyList() { return m_propertyList; }
+
+ static TransitionProperty initialProperty() { return TransitionProperty(TransitionAll); }
+
+private:
+ CSSTransitionData();
+ explicit CSSTransitionData(const CSSTransitionData&);
+
+ Vector<TransitionProperty> m_propertyList;
+};
+
+} // namespace WebCore
+
+#endif // CSSTransitionData_h
diff --git a/chromium/third_party/WebKit/Source/core/animation/interpolation/DefaultStyleInterpolation.h b/chromium/third_party/WebKit/Source/core/animation/interpolation/DefaultStyleInterpolation.h
new file mode 100644
index 00000000000..174c12b9fdd
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/interpolation/DefaultStyleInterpolation.h
@@ -0,0 +1,46 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef DefaultStyleInterpolation_h
+#define DefaultStyleInterpolation_h
+
+#include "core/animation/interpolation/StyleInterpolation.h"
+#include "core/css/resolver/StyleBuilder.h"
+
+namespace WebCore {
+
+class DefaultStyleInterpolation : public StyleInterpolation {
+public:
+ static PassRefPtrWillBeRawPtr<DefaultStyleInterpolation> create(CSSValue* start, CSSValue* end, CSSPropertyID id)
+ {
+ return adoptRefWillBeNoop(new DefaultStyleInterpolation(start, end, id));
+ }
+
+ virtual void apply(StyleResolverState& state) const
+ {
+ StyleBuilder::applyProperty(m_id, state, toInterpolableBool(m_cachedValue.get())->value() ? m_endCSSValue.get() : m_startCSSValue.get());
+ }
+
+ virtual void trace(Visitor* visitor) OVERRIDE
+ {
+ StyleInterpolation::trace(visitor);
+ visitor->trace(m_startCSSValue);
+ visitor->trace(m_endCSSValue);
+ }
+
+private:
+ DefaultStyleInterpolation(CSSValue* start, CSSValue* end, CSSPropertyID id)
+ : StyleInterpolation(InterpolableBool::create(false), InterpolableBool::create(true), id)
+ , m_startCSSValue(start)
+ , m_endCSSValue(end)
+ {
+ }
+
+ RefPtrWillBeMember<CSSValue> m_startCSSValue;
+ RefPtrWillBeMember<CSSValue> m_endCSSValue;
+};
+
+}
+
+#endif
diff --git a/chromium/third_party/WebKit/Source/core/animation/interpolation/DeferredLegacyStyleInterpolation.cpp b/chromium/third_party/WebKit/Source/core/animation/interpolation/DeferredLegacyStyleInterpolation.cpp
new file mode 100644
index 00000000000..6a0be63049c
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/interpolation/DeferredLegacyStyleInterpolation.cpp
@@ -0,0 +1,152 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "config.h"
+#include "core/animation/interpolation/DeferredLegacyStyleInterpolation.h"
+
+#include "core/animation/interpolation/LegacyStyleInterpolation.h"
+#include "core/css/CSSImageValue.h"
+#include "core/css/CSSPrimitiveValue.h"
+#include "core/css/CSSSVGDocumentValue.h"
+#include "core/css/CSSShadowValue.h"
+#include "core/css/CSSValueList.h"
+#include "core/css/Pair.h"
+#include "core/css/Rect.h"
+#include "core/css/resolver/StyleResolver.h"
+#include "core/css/resolver/StyleResolverState.h"
+
+namespace WebCore {
+
+void DeferredLegacyStyleInterpolation::apply(StyleResolverState& state) const
+{
+ RefPtrWillBeRawPtr<LegacyStyleInterpolation> innerInterpolation = LegacyStyleInterpolation::create(
+ StyleResolver::createAnimatableValueSnapshot(state, m_id, *m_startCSSValue),
+ StyleResolver::createAnimatableValueSnapshot(state, m_id, *m_endCSSValue),
+ m_id);
+ innerInterpolation->interpolate(m_cachedIteration, m_cachedFraction);
+ innerInterpolation->apply(state);
+}
+
+bool DeferredLegacyStyleInterpolation::interpolationRequiresStyleResolve(const CSSValue& value)
+{
+ switch (value.cssValueType()) {
+ case CSSValue::CSS_INHERIT:
+ return true;
+ case CSSValue::CSS_PRIMITIVE_VALUE:
+ return interpolationRequiresStyleResolve(toCSSPrimitiveValue(value));
+ case CSSValue::CSS_VALUE_LIST:
+ return interpolationRequiresStyleResolve(toCSSValueList(value));
+ case CSSValue::CSS_CUSTOM:
+ if (value.isImageValue())
+ return interpolationRequiresStyleResolve(toCSSImageValue(value));
+ if (value.isShadowValue())
+ return interpolationRequiresStyleResolve(toCSSShadowValue(value));
+ if (value.isSVGDocumentValue())
+ return interpolationRequiresStyleResolve(toCSSSVGDocumentValue(value));
+ // FIXME: consider other custom types.
+ return true;
+ case CSSValue::CSS_INITIAL:
+ // FIXME: should not require resolving styles for initial.
+ return true;
+ default:
+ ASSERT_NOT_REACHED();
+ return true;
+ }
+}
+
+bool DeferredLegacyStyleInterpolation::interpolationRequiresStyleResolve(const CSSPrimitiveValue& primitiveValue)
+{
+ // FIXME: consider other types.
+ if (primitiveValue.isNumber() || primitiveValue.isPercentage() || primitiveValue.isAngle() || primitiveValue.isRGBColor() || primitiveValue.isURI())
+ return false;
+
+ if (primitiveValue.isLength())
+ return primitiveValue.isFontRelativeLength() || primitiveValue.isViewportPercentageLength();
+
+ if (primitiveValue.isCalculated()) {
+ CSSLengthArray lengthArray(CSSPrimitiveValue::LengthUnitTypeCount);
+ primitiveValue.accumulateLengthArray(lengthArray);
+ return lengthArray[CSSPrimitiveValue::UnitTypeFontSize] != 0
+ || lengthArray[CSSPrimitiveValue::UnitTypeFontXSize] != 0
+ || lengthArray[CSSPrimitiveValue::UnitTypeRootFontSize] != 0
+ || lengthArray[CSSPrimitiveValue::UnitTypeZeroCharacterWidth] != 0
+ || lengthArray[CSSPrimitiveValue::UnitTypeViewportWidth] != 0
+ || lengthArray[CSSPrimitiveValue::UnitTypeViewportHeight] != 0
+ || lengthArray[CSSPrimitiveValue::UnitTypeViewportMin] != 0
+ || lengthArray[CSSPrimitiveValue::UnitTypeViewportMax] != 0;
+ }
+
+ if (Pair* pair = primitiveValue.getPairValue()) {
+ return interpolationRequiresStyleResolve(*pair->first())
+ || interpolationRequiresStyleResolve(*pair->second());
+ }
+
+ if (Rect* rect = primitiveValue.getRectValue()) {
+ return interpolationRequiresStyleResolve(*rect->top())
+ || interpolationRequiresStyleResolve(*rect->right())
+ || interpolationRequiresStyleResolve(*rect->bottom())
+ || interpolationRequiresStyleResolve(*rect->left());
+ }
+
+ if (Quad* quad = primitiveValue.getQuadValue()) {
+ return interpolationRequiresStyleResolve(*quad->top())
+ || interpolationRequiresStyleResolve(*quad->right())
+ || interpolationRequiresStyleResolve(*quad->bottom())
+ || interpolationRequiresStyleResolve(*quad->left());
+ }
+
+ if (primitiveValue.isShape())
+ return interpolationRequiresStyleResolve(*primitiveValue.getShapeValue());
+
+ CSSValueID id = primitiveValue.getValueID();
+ bool isColor = ((id >= CSSValueAqua && id <= CSSValueTransparent)
+ || (id >= CSSValueAliceblue && id <= CSSValueYellowgreen)
+ || id == CSSValueGrey);
+ return (id != CSSValueNone) && !isColor;
+}
+
+bool DeferredLegacyStyleInterpolation::interpolationRequiresStyleResolve(const CSSImageValue& imageValue)
+{
+ return false;
+}
+
+bool DeferredLegacyStyleInterpolation::interpolationRequiresStyleResolve(const CSSShadowValue& shadowValue)
+{
+ return (shadowValue.x && interpolationRequiresStyleResolve(*shadowValue.x))
+ || (shadowValue.y && interpolationRequiresStyleResolve(*shadowValue.y))
+ || (shadowValue.blur && interpolationRequiresStyleResolve(*shadowValue.blur))
+ || (shadowValue.spread && interpolationRequiresStyleResolve(*shadowValue.spread))
+ || (shadowValue.style && interpolationRequiresStyleResolve(*shadowValue.style))
+ || (shadowValue.color && interpolationRequiresStyleResolve(*shadowValue.color));
+}
+
+bool DeferredLegacyStyleInterpolation::interpolationRequiresStyleResolve(const CSSSVGDocumentValue& documentValue)
+{
+ return true;
+}
+
+bool DeferredLegacyStyleInterpolation::interpolationRequiresStyleResolve(const CSSValueList& valueList)
+{
+ size_t length = valueList.length();
+ for (size_t index = 0; index < length; ++index) {
+ if (interpolationRequiresStyleResolve(*valueList.item(index)))
+ return true;
+ }
+ return false;
+}
+
+bool DeferredLegacyStyleInterpolation::interpolationRequiresStyleResolve(const CSSBasicShape& shape)
+{
+ // FIXME: Should determine the specific shape, and inspect the members.
+ return false;
+}
+
+void DeferredLegacyStyleInterpolation::trace(Visitor* visitor)
+{
+ visitor->trace(m_startCSSValue);
+ visitor->trace(m_endCSSValue);
+ StyleInterpolation::trace(visitor);
+}
+
+}
diff --git a/chromium/third_party/WebKit/Source/core/animation/interpolation/DeferredLegacyStyleInterpolation.h b/chromium/third_party/WebKit/Source/core/animation/interpolation/DeferredLegacyStyleInterpolation.h
new file mode 100644
index 00000000000..f1737bae269
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/interpolation/DeferredLegacyStyleInterpolation.h
@@ -0,0 +1,53 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef DeferredLegacyStyleInterpolation_h
+#define DeferredLegacyStyleInterpolation_h
+
+#include "core/animation/interpolation/StyleInterpolation.h"
+#include "core/css/CSSValue.h"
+
+namespace WebCore {
+
+class CSSBasicShape;
+class CSSImageValue;
+class CSSPrimitiveValue;
+class CSSShadowValue;
+class CSSSVGDocumentValue;
+class CSSValueList;
+
+class DeferredLegacyStyleInterpolation : public StyleInterpolation {
+public:
+ static PassRefPtrWillBeRawPtr<DeferredLegacyStyleInterpolation> create(PassRefPtrWillBeRawPtr<CSSValue> start, PassRefPtrWillBeRawPtr<CSSValue> end, CSSPropertyID id)
+ {
+ return adoptRefWillBeNoop(new DeferredLegacyStyleInterpolation(start, end, id));
+ }
+
+ virtual void apply(StyleResolverState&) const OVERRIDE;
+
+ virtual void trace(Visitor*) OVERRIDE;
+
+ static bool interpolationRequiresStyleResolve(const CSSValue&);
+ static bool interpolationRequiresStyleResolve(const CSSPrimitiveValue&);
+ static bool interpolationRequiresStyleResolve(const CSSImageValue&);
+ static bool interpolationRequiresStyleResolve(const CSSShadowValue&);
+ static bool interpolationRequiresStyleResolve(const CSSSVGDocumentValue&);
+ static bool interpolationRequiresStyleResolve(const CSSValueList&);
+ static bool interpolationRequiresStyleResolve(const CSSBasicShape&);
+
+private:
+ DeferredLegacyStyleInterpolation(PassRefPtrWillBeRawPtr<CSSValue> start, PassRefPtrWillBeRawPtr<CSSValue> end, CSSPropertyID id)
+ : StyleInterpolation(InterpolableNumber::create(0), InterpolableNumber::create(1), id)
+ , m_startCSSValue(start)
+ , m_endCSSValue(end)
+ {
+ }
+
+ RefPtrWillBeMember<CSSValue> m_startCSSValue;
+ RefPtrWillBeMember<CSSValue> m_endCSSValue;
+};
+
+}
+
+#endif
diff --git a/chromium/third_party/WebKit/Source/core/animation/interpolation/DeferredLegacyStyleInterpolationTest.cpp b/chromium/third_party/WebKit/Source/core/animation/interpolation/DeferredLegacyStyleInterpolationTest.cpp
new file mode 100644
index 00000000000..4c851f9648f
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/interpolation/DeferredLegacyStyleInterpolationTest.cpp
@@ -0,0 +1,94 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "config.h"
+#include "core/animation/interpolation/DeferredLegacyStyleInterpolation.h"
+
+#include "core/css/CSSInheritedValue.h"
+#include "core/css/CSSPrimitiveValue.h"
+#include "core/css/CSSValueList.h"
+#include "core/css/StylePropertySet.h"
+#include "core/css/parser/BisonCSSParser.h"
+
+#include <gtest/gtest.h>
+
+namespace WebCore {
+
+class AnimationDeferredLegacyStyleInterpolationTest : public ::testing::Test {
+protected:
+ static bool test(CSSPropertyID propertyID, const String& string)
+ {
+ CSSParserMode parserMode = HTMLStandardMode;
+ if (propertyID == CSSPropertyFloodColor)
+ parserMode = SVGAttributeMode;
+ RefPtrWillBeRawPtr<MutableStylePropertySet> dummyStyle = MutableStylePropertySet::create();
+ bool parseSuccess = BisonCSSParser::parseValue(dummyStyle.get(), propertyID, string, false, parserMode, 0);
+ ASSERT_UNUSED(parseSuccess, parseSuccess);
+ return DeferredLegacyStyleInterpolation::interpolationRequiresStyleResolve(*dummyStyle->getPropertyCSSValue(propertyID));
+ }
+};
+
+TEST_F(AnimationDeferredLegacyStyleInterpolationTest, Inherit)
+{
+ EXPECT_TRUE(test(CSSPropertyCaptionSide, "inherit"));
+}
+
+TEST_F(AnimationDeferredLegacyStyleInterpolationTest, Color)
+{
+ EXPECT_FALSE(test(CSSPropertyColor, "rgb(10, 20, 30)"));
+ EXPECT_FALSE(test(CSSPropertyColor, "aqua"));
+ EXPECT_FALSE(test(CSSPropertyColor, "yellow"));
+ EXPECT_FALSE(test(CSSPropertyColor, "transparent"));
+ EXPECT_FALSE(test(CSSPropertyFloodColor, "aliceblue"));
+ EXPECT_FALSE(test(CSSPropertyFloodColor, "yellowgreen"));
+ EXPECT_FALSE(test(CSSPropertyFloodColor, "grey"));
+ EXPECT_TRUE(test(CSSPropertyColor, "currentcolor"));
+}
+
+TEST_F(AnimationDeferredLegacyStyleInterpolationTest, Relative)
+{
+ EXPECT_TRUE(test(CSSPropertyFontWeight, "bolder"));
+ EXPECT_TRUE(test(CSSPropertyFontWeight, "lighter"));
+ EXPECT_TRUE(test(CSSPropertyFontSize, "smaller"));
+ EXPECT_TRUE(test(CSSPropertyFontSize, "larger"));
+}
+
+TEST_F(AnimationDeferredLegacyStyleInterpolationTest, Length)
+{
+ EXPECT_FALSE(test(CSSPropertyWidth, "10px"));
+ EXPECT_TRUE(test(CSSPropertyWidth, "10em"));
+ EXPECT_TRUE(test(CSSPropertyWidth, "10vh"));
+}
+
+TEST_F(AnimationDeferredLegacyStyleInterpolationTest, Number)
+{
+ EXPECT_FALSE(test(CSSPropertyOpacity, "0.5"));
+}
+
+TEST_F(AnimationDeferredLegacyStyleInterpolationTest, Transform)
+{
+ EXPECT_TRUE(test(CSSPropertyTransform, "translateX(1em)"));
+ EXPECT_FALSE(test(CSSPropertyTransform, "translateY(20px)"));
+ EXPECT_FALSE(test(CSSPropertyTransform, "skewX(10rad) perspective(400px)"));
+ EXPECT_TRUE(test(CSSPropertyTransform, "skewX(20rad) perspective(50em)"));
+}
+
+TEST_F(AnimationDeferredLegacyStyleInterpolationTest, Filter)
+{
+ EXPECT_FALSE(test(CSSPropertyWebkitFilter, "hue-rotate(180deg) blur(6px)"));
+ EXPECT_FALSE(test(CSSPropertyWebkitFilter, "grayscale(0) blur(0px)"));
+ EXPECT_FALSE(test(CSSPropertyWebkitFilter, "none"));
+ EXPECT_FALSE(test(CSSPropertyWebkitFilter, "brightness(0) contrast(0)"));
+ EXPECT_FALSE(test(CSSPropertyWebkitFilter, "drop-shadow(20px 10px green)"));
+ EXPECT_TRUE(test(CSSPropertyWebkitFilter, "drop-shadow(20px 10vw green)"));
+ EXPECT_TRUE(test(CSSPropertyWebkitFilter, "drop-shadow(0px 0px 0px currentcolor)"));
+ EXPECT_FALSE(test(CSSPropertyWebkitFilter, "opacity(1)"));
+ EXPECT_FALSE(test(CSSPropertyWebkitFilter, "saturate(0)"));
+ EXPECT_FALSE(test(CSSPropertyWebkitFilter, "grayscale(1)"));
+ EXPECT_FALSE(test(CSSPropertyWebkitFilter, "invert(1)"));
+ EXPECT_FALSE(test(CSSPropertyWebkitFilter, "sepia(1)"));
+ EXPECT_TRUE(test(CSSPropertyWebkitFilter, "url(#svgfilter)"));
+}
+
+}
diff --git a/chromium/third_party/WebKit/Source/core/animation/interpolation/Interpolation.cpp b/chromium/third_party/WebKit/Source/core/animation/interpolation/Interpolation.cpp
new file mode 100644
index 00000000000..1ba5c6d74a8
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/interpolation/Interpolation.cpp
@@ -0,0 +1,63 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "config.h"
+#include "core/animation/interpolation/Interpolation.h"
+
+namespace WebCore {
+
+DEFINE_EMPTY_DESTRUCTOR_WILL_BE_REMOVED(Interpolation);
+
+namespace {
+
+bool typesMatch(const InterpolableValue* start, const InterpolableValue* end)
+{
+ if (start->isNumber())
+ return end->isNumber();
+ if (start->isBool())
+ return end->isBool();
+ if (start->isAnimatableValue())
+ return end->isAnimatableValue();
+ if (!(start->isList() && end->isList()))
+ return false;
+ const InterpolableList* startList = toInterpolableList(start);
+ const InterpolableList* endList = toInterpolableList(end);
+ if (startList->length() != endList->length())
+ return false;
+ for (size_t i = 0; i < startList->length(); ++i) {
+ if (!typesMatch(startList->get(i), endList->get(i)))
+ return false;
+ }
+ return true;
+}
+
+}
+
+Interpolation::Interpolation(PassOwnPtrWillBeRawPtr<InterpolableValue> start, PassOwnPtrWillBeRawPtr<InterpolableValue> end)
+ : m_start(start)
+ , m_end(end)
+ , m_cachedFraction(0)
+ , m_cachedIteration(0)
+ , m_cachedValue(m_start->clone())
+{
+ RELEASE_ASSERT(typesMatch(m_start.get(), m_end.get()));
+}
+
+void Interpolation::interpolate(int iteration, double fraction) const
+{
+ if (m_cachedFraction != fraction || m_cachedIteration != iteration) {
+ m_cachedValue = m_start->interpolate(*m_end, fraction);
+ m_cachedIteration = iteration;
+ m_cachedFraction = fraction;
+ }
+}
+
+void Interpolation::trace(Visitor* visitor)
+{
+ visitor->trace(m_start);
+ visitor->trace(m_end);
+ visitor->trace(m_cachedValue);
+}
+
+}
diff --git a/chromium/third_party/WebKit/Source/core/animation/interpolation/Interpolation.h b/chromium/third_party/WebKit/Source/core/animation/interpolation/Interpolation.h
new file mode 100644
index 00000000000..ffa62b0cfca
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/interpolation/Interpolation.h
@@ -0,0 +1,47 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef Interpolation_h
+#define Interpolation_h
+
+#include "core/animation/InterpolableValue.h"
+#include "platform/heap/Handle.h"
+
+namespace WebCore {
+
+class Interpolation : public RefCountedWillBeGarbageCollected<Interpolation> {
+ DECLARE_EMPTY_VIRTUAL_DESTRUCTOR_WILL_BE_REMOVED(Interpolation);
+public:
+ static PassRefPtrWillBeRawPtr<Interpolation> create(PassOwnPtrWillBeRawPtr<InterpolableValue> start, PassOwnPtrWillBeRawPtr<InterpolableValue> end)
+ {
+ return adoptRefWillBeNoop(new Interpolation(start, end));
+ }
+
+ void interpolate(int iteration, double fraction) const;
+
+ virtual bool isStyleInterpolation() const { return false; }
+ virtual bool isLegacyStyleInterpolation() const { return false; }
+
+ virtual void trace(Visitor*);
+
+protected:
+ const OwnPtrWillBeMember<InterpolableValue> m_start;
+ const OwnPtrWillBeMember<InterpolableValue> m_end;
+
+ mutable double m_cachedFraction;
+ mutable int m_cachedIteration;
+ mutable OwnPtrWillBeMember<InterpolableValue> m_cachedValue;
+
+ Interpolation(PassOwnPtrWillBeRawPtr<InterpolableValue> start, PassOwnPtrWillBeRawPtr<InterpolableValue> end);
+
+private:
+ InterpolableValue* getCachedValueForTesting() const { return m_cachedValue.get(); }
+
+ friend class AnimationInterpolableValueTest;
+ friend class AnimationInterpolationEffectTest;
+};
+
+}
+
+#endif
diff --git a/chromium/third_party/WebKit/Source/core/animation/interpolation/LegacyStyleInterpolation.h b/chromium/third_party/WebKit/Source/core/animation/interpolation/LegacyStyleInterpolation.h
new file mode 100644
index 00000000000..d16bd994f4a
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/interpolation/LegacyStyleInterpolation.h
@@ -0,0 +1,48 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LegacyStyleInterpolation_h
+#define LegacyStyleInterpolation_h
+
+#include "core/animation/interpolation/StyleInterpolation.h"
+#include "core/css/resolver/AnimatedStyleBuilder.h"
+
+namespace WebCore {
+
+class LegacyStyleInterpolation : public StyleInterpolation {
+public:
+ static PassRefPtrWillBeRawPtr<LegacyStyleInterpolation> create(PassRefPtrWillBeRawPtr<AnimatableValue> start, PassRefPtrWillBeRawPtr<AnimatableValue> end, CSSPropertyID id)
+ {
+ return adoptRefWillBeNoop(new LegacyStyleInterpolation(InterpolableAnimatableValue::create(start), InterpolableAnimatableValue::create(end), id));
+ }
+
+ virtual void apply(StyleResolverState& state) const OVERRIDE
+ {
+ AnimatedStyleBuilder::applyProperty(m_id, state, currentValue().get());
+ }
+
+ virtual bool isLegacyStyleInterpolation() const OVERRIDE FINAL { return true; }
+ PassRefPtrWillBeRawPtr<AnimatableValue> currentValue() const
+ {
+ InterpolableAnimatableValue* value = static_cast<InterpolableAnimatableValue*>(m_cachedValue.get());
+ return value->value();
+ }
+
+ virtual void trace(Visitor* visitor) OVERRIDE
+ {
+ StyleInterpolation::trace(visitor);
+ }
+
+private:
+ LegacyStyleInterpolation(PassOwnPtrWillBeRawPtr<InterpolableValue> start, PassOwnPtrWillBeRawPtr<InterpolableValue> end, CSSPropertyID id)
+ : StyleInterpolation(start, end, id)
+ {
+ }
+};
+
+DEFINE_TYPE_CASTS(LegacyStyleInterpolation, Interpolation, value, value->isLegacyStyleInterpolation(), value.isLegacyStyleInterpolation());
+
+}
+
+#endif
diff --git a/chromium/third_party/WebKit/Source/core/animation/interpolation/LengthStyleInterpolation.cpp b/chromium/third_party/WebKit/Source/core/animation/interpolation/LengthStyleInterpolation.cpp
new file mode 100644
index 00000000000..013d3067be6
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/interpolation/LengthStyleInterpolation.cpp
@@ -0,0 +1,109 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "config.h"
+#include "core/animation/interpolation/LengthStyleInterpolation.h"
+
+#include "core/css/CSSCalculationValue.h"
+#include "core/css/resolver/StyleBuilder.h"
+
+namespace WebCore {
+
+bool LengthStyleInterpolation::canCreateFrom(const CSSValue& value)
+{
+ if (value.isPrimitiveValue()) {
+ const CSSPrimitiveValue& primitiveValue = WebCore::toCSSPrimitiveValue(value);
+ if (primitiveValue.cssCalcValue())
+ return true;
+
+ CSSPrimitiveValue::LengthUnitType type;
+ // Only returns true if the type is a primitive length unit.
+ return CSSPrimitiveValue::unitTypeToLengthUnitType(primitiveValue.primitiveType(), type);
+ }
+ return value.isCalcValue();
+}
+
+PassOwnPtrWillBeRawPtr<InterpolableValue> LengthStyleInterpolation::lengthToInterpolableValue(CSSValue* value)
+{
+ OwnPtrWillBeRawPtr<InterpolableList> result = InterpolableList::create(CSSPrimitiveValue::LengthUnitTypeCount);
+ CSSPrimitiveValue* primitive = toCSSPrimitiveValue(value);
+
+ CSSLengthArray array;
+ for (size_t i = 0; i < CSSPrimitiveValue::LengthUnitTypeCount; i++)
+ array.append(0);
+ primitive->accumulateLengthArray(array);
+
+ for (size_t i = 0; i < CSSPrimitiveValue::LengthUnitTypeCount; i++)
+ result->set(i, InterpolableNumber::create(array.at(i)));
+
+ return result.release();
+}
+
+namespace {
+
+static CSSPrimitiveValue::UnitType toUnitType(int lengthUnitType)
+{
+ return static_cast<CSSPrimitiveValue::UnitType>(CSSPrimitiveValue::lengthUnitTypeToUnitType(static_cast<CSSPrimitiveValue::LengthUnitType>(lengthUnitType)));
+}
+
+static PassRefPtrWillBeRawPtr<CSSCalcExpressionNode> constructCalcExpression(PassRefPtrWillBeRawPtr<CSSCalcExpressionNode> previous, InterpolableList* list, size_t position)
+{
+ while (position != CSSPrimitiveValue::LengthUnitTypeCount) {
+ const InterpolableNumber *subValue = toInterpolableNumber(list->get(position));
+ if (subValue->value()) {
+ RefPtrWillBeRawPtr<CSSCalcExpressionNode> next;
+ if (previous)
+ next = CSSCalcValue::createExpressionNode(previous, CSSCalcValue::createExpressionNode(CSSPrimitiveValue::create(subValue->value(), toUnitType(position))), CalcAdd);
+ else
+ next = CSSCalcValue::createExpressionNode(CSSPrimitiveValue::create(subValue->value(), toUnitType(position)));
+ return constructCalcExpression(next, list, position + 1);
+ }
+ position++;
+ }
+ return previous;
+}
+
+}
+
+PassRefPtrWillBeRawPtr<CSSValue> LengthStyleInterpolation::interpolableValueToLength(InterpolableValue* value, ValueRange range)
+{
+ InterpolableList* listValue = toInterpolableList(value);
+ unsigned unitCount = 0;
+ for (size_t i = 0; i < CSSPrimitiveValue::LengthUnitTypeCount; i++) {
+ const InterpolableNumber* subValue = toInterpolableNumber(listValue->get(i));
+ if (subValue->value()) {
+ unitCount++;
+ }
+ }
+
+ switch (unitCount) {
+ case 0:
+ return CSSPrimitiveValue::create(0, CSSPrimitiveValue::CSS_PX);
+ case 1:
+ for (size_t i = 0; i < CSSPrimitiveValue::LengthUnitTypeCount; i++) {
+ const InterpolableNumber* subValue = toInterpolableNumber(listValue->get(i));
+ double value = subValue->value();
+ if (value) {
+ if (range == ValueRangeNonNegative && value < 0)
+ value = 0;
+ return CSSPrimitiveValue::create(value, toUnitType(i));
+ }
+ }
+ ASSERT_NOT_REACHED();
+ default:
+ return CSSPrimitiveValue::create(CSSCalcValue::create(constructCalcExpression(nullptr, listValue, 0), range));
+ }
+}
+
+void LengthStyleInterpolation::apply(StyleResolverState& state) const
+{
+ StyleBuilder::applyProperty(m_id, state, interpolableValueToLength(m_cachedValue.get(), m_range).get());
+}
+
+void LengthStyleInterpolation::trace(Visitor* visitor)
+{
+ StyleInterpolation::trace(visitor);
+}
+
+}
diff --git a/chromium/third_party/WebKit/Source/core/animation/interpolation/LengthStyleInterpolation.h b/chromium/third_party/WebKit/Source/core/animation/interpolation/LengthStyleInterpolation.h
new file mode 100644
index 00000000000..d344957da8c
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/interpolation/LengthStyleInterpolation.h
@@ -0,0 +1,42 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LengthStyleInterpolation_h
+#define LengthStyleInterpolation_h
+
+#include "core/animation/interpolation/StyleInterpolation.h"
+#include "platform/Length.h"
+
+namespace WebCore {
+
+class LengthStyleInterpolation : public StyleInterpolation {
+public:
+ static PassRefPtrWillBeRawPtr<LengthStyleInterpolation> create(CSSValue* start, CSSValue* end, CSSPropertyID id, ValueRange range)
+ {
+ return adoptRefWillBeNoop(new LengthStyleInterpolation(lengthToInterpolableValue(start), lengthToInterpolableValue(end), id, range));
+ }
+
+ static bool canCreateFrom(const CSSValue&);
+
+ virtual void apply(StyleResolverState&) const OVERRIDE;
+
+ virtual void trace(Visitor*) OVERRIDE;
+
+private:
+ LengthStyleInterpolation(PassOwnPtrWillBeRawPtr<InterpolableValue> start, PassOwnPtrWillBeRawPtr<InterpolableValue> end, CSSPropertyID id, ValueRange range)
+ : StyleInterpolation(start, end, id)
+ , m_range(range)
+ { }
+
+ static PassOwnPtrWillBeRawPtr<InterpolableValue> lengthToInterpolableValue(CSSValue*);
+ static PassRefPtrWillBeRawPtr<CSSValue> interpolableValueToLength(InterpolableValue*, ValueRange);
+
+ ValueRange m_range;
+
+ friend class AnimationLengthStyleInterpolationTest;
+};
+
+}
+
+#endif
diff --git a/chromium/third_party/WebKit/Source/core/animation/interpolation/LengthStyleInterpolationTest.cpp b/chromium/third_party/WebKit/Source/core/animation/interpolation/LengthStyleInterpolationTest.cpp
new file mode 100644
index 00000000000..8120e846fdf
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/interpolation/LengthStyleInterpolationTest.cpp
@@ -0,0 +1,119 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "config.h"
+#include "core/animation/interpolation/LengthStyleInterpolation.h"
+
+#include "core/css/CSSPrimitiveValue.h"
+#include "core/css/StylePropertySet.h"
+
+#include <gtest/gtest.h>
+
+namespace WebCore {
+
+class AnimationLengthStyleInterpolationTest : public ::testing::Test {
+protected:
+ static PassOwnPtrWillBeRawPtr<InterpolableValue> lengthToInterpolableValue(CSSValue* value)
+ {
+ return LengthStyleInterpolation::lengthToInterpolableValue(value);
+ }
+
+ static PassRefPtrWillBeRawPtr<CSSValue> interpolableValueToLength(InterpolableValue* value, ValueRange range)
+ {
+ return LengthStyleInterpolation::interpolableValueToLength(value, range);
+ }
+
+ static PassRefPtrWillBeRawPtr<CSSValue> roundTrip(PassRefPtrWillBeRawPtr<CSSValue> value)
+ {
+ return interpolableValueToLength(lengthToInterpolableValue(value.get()).get(), ValueRangeAll);
+ }
+
+ static void testPrimitiveValue(RefPtrWillBeRawPtr<CSSValue> value, double doubleValue, CSSPrimitiveValue::UnitType unitType)
+ {
+ EXPECT_TRUE(value->isPrimitiveValue());
+ EXPECT_EQ(doubleValue, toCSSPrimitiveValue(value.get())->getDoubleValue());
+ EXPECT_EQ(unitType, toCSSPrimitiveValue(value.get())->primitiveType());
+ }
+
+ static PassOwnPtrWillBeRawPtr<InterpolableList> createInterpolableLength(double a, double b, double c, double d, double e, double f, double g, double h, double i, double j)
+ {
+ OwnPtrWillBeRawPtr<InterpolableList> list = InterpolableList::create(10);
+ list->set(0, InterpolableNumber::create(a));
+ list->set(1, InterpolableNumber::create(b));
+ list->set(2, InterpolableNumber::create(c));
+ list->set(3, InterpolableNumber::create(d));
+ list->set(4, InterpolableNumber::create(e));
+ list->set(5, InterpolableNumber::create(f));
+ list->set(6, InterpolableNumber::create(g));
+ list->set(7, InterpolableNumber::create(h));
+ list->set(8, InterpolableNumber::create(i));
+ list->set(9, InterpolableNumber::create(j));
+
+ return list.release();
+ }
+
+ void initLengthArray(CSSLengthArray& lengthArray)
+ {
+ lengthArray.resize(CSSPrimitiveValue::LengthUnitTypeCount);
+ for (size_t i = 0; i < CSSPrimitiveValue::LengthUnitTypeCount; ++i)
+ lengthArray.at(i) = 0;
+ }
+
+ CSSLengthArray& setLengthArray(CSSLengthArray& lengthArray, String text)
+ {
+ initLengthArray(lengthArray);
+ RefPtr<MutableStylePropertySet> propertySet = MutableStylePropertySet::create();
+ propertySet->setProperty(CSSPropertyLeft, text);
+ toCSSPrimitiveValue(propertySet->getPropertyCSSValue(CSSPropertyLeft).get())->accumulateLengthArray(lengthArray);
+ return lengthArray;
+ }
+
+ bool lengthArraysEqual(CSSLengthArray& a, CSSLengthArray& b)
+ {
+ for (size_t i = 0; i < CSSPrimitiveValue::LengthUnitTypeCount; ++i) {
+ if (a.at(i) != b.at(i))
+ return false;
+ }
+ return true;
+ }
+};
+
+TEST_F(AnimationLengthStyleInterpolationTest, ZeroLength)
+{
+ RefPtrWillBeRawPtr<CSSValue> value = roundTrip(CSSPrimitiveValue::create(0, CSSPrimitiveValue::CSS_PX));
+ testPrimitiveValue(value, 0, CSSPrimitiveValue::CSS_PX);
+
+ value = roundTrip(CSSPrimitiveValue::create(0, CSSPrimitiveValue::CSS_EMS));
+ testPrimitiveValue(value, 0, CSSPrimitiveValue::CSS_PX);
+}
+
+TEST_F(AnimationLengthStyleInterpolationTest, SingleUnit)
+{
+ RefPtrWillBeRawPtr<CSSValue> value = roundTrip(CSSPrimitiveValue::create(10, CSSPrimitiveValue::CSS_PX));
+ testPrimitiveValue(value, 10, CSSPrimitiveValue::CSS_PX);
+
+ value = roundTrip(CSSPrimitiveValue::create(30, CSSPrimitiveValue::CSS_PERCENTAGE));
+ testPrimitiveValue(value, 30, CSSPrimitiveValue::CSS_PERCENTAGE);
+
+ value = roundTrip(CSSPrimitiveValue::create(-10, CSSPrimitiveValue::CSS_EMS));
+ testPrimitiveValue(value, -10, CSSPrimitiveValue::CSS_EMS);
+}
+
+TEST_F(AnimationLengthStyleInterpolationTest, SingleClampedUnit)
+{
+ RefPtrWillBeRawPtr<CSSValue> value = CSSPrimitiveValue::create(-10, CSSPrimitiveValue::CSS_EMS);
+ value = interpolableValueToLength(lengthToInterpolableValue(value.get()).get(), ValueRangeNonNegative);
+ testPrimitiveValue(value, 0, CSSPrimitiveValue::CSS_EMS);
+}
+
+TEST_F(AnimationLengthStyleInterpolationTest, MultipleUnits)
+{
+ CSSLengthArray actual, expectation;
+ initLengthArray(expectation);
+ OwnPtrWillBeRawPtr<InterpolableList> list = createInterpolableLength(0, 10, 0, 10, 0, 10, 0, 10, 0, 10);
+ toCSSPrimitiveValue(interpolableValueToLength(list.get(), ValueRangeAll).get())->accumulateLengthArray(expectation);
+ EXPECT_TRUE(lengthArraysEqual(expectation, setLengthArray(actual, "calc(10%% + 10ex + 10ch + 10vh + 10vmax)")));
+}
+
+}
diff --git a/chromium/third_party/WebKit/Source/core/animation/interpolation/StyleInterpolation.h b/chromium/third_party/WebKit/Source/core/animation/interpolation/StyleInterpolation.h
new file mode 100644
index 00000000000..5c277439ffd
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/core/animation/interpolation/StyleInterpolation.h
@@ -0,0 +1,48 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef StyleInterpolation_h
+#define StyleInterpolation_h
+
+#include "core/CSSPropertyNames.h"
+#include "core/animation/interpolation/Interpolation.h"
+
+namespace WebCore {
+
+class StyleResolverState;
+
+class StyleInterpolation : public Interpolation {
+public:
+ // 1) convert m_cachedValue into an X
+ // 2) shove X into StyleResolverState
+ // X can be:
+ // (1) a CSSValue (and applied via StyleBuilder::applyProperty)
+ // (2) an AnimatableValue (and applied via // AnimatedStyleBuilder::applyProperty)
+ // (3) a custom value that is inserted directly into the StyleResolverState.
+ virtual void apply(StyleResolverState&) const = 0;
+
+ virtual bool isStyleInterpolation() const OVERRIDE FINAL { return true; }
+
+ CSSPropertyID id() const { return m_id; }
+
+ virtual void trace(Visitor* visitor) OVERRIDE
+ {
+ Interpolation::trace(visitor);
+ }
+
+protected:
+ CSSPropertyID m_id;
+
+ StyleInterpolation(PassOwnPtrWillBeRawPtr<InterpolableValue> start, PassOwnPtrWillBeRawPtr<InterpolableValue> end, CSSPropertyID id)
+ : Interpolation(start, end)
+ , m_id(id)
+ {
+ }
+};
+
+DEFINE_TYPE_CASTS(StyleInterpolation, Interpolation, value, value->isStyleInterpolation(), value.isStyleInterpolation());
+
+}
+
+#endif