Commit e4ca9eb0 authored by shans@chromium.org's avatar shans@chromium.org

Web Animations: Introduce String based KeyframeEffectModel

Note: This is a rework of issue 212023004

This patch refactors KeyframeEffectModel to support different types of
keyframe values. The common keyframe logic is retained in
KeyframeEffectModelBase to be inherited by the keyframe type specialisations.

KeyframeEffectModel is then templated on Keyframe type, with a hierarchy of Keyframes
including StringKeyframe and AnimatableValueKeyframe being introduced.

String based keyframes are being introduced to properly support the JS API
for Web Animations element.animate().

Review URL: https://codereview.chromium.org/215883005

git-svn-id: svn://svn.chromium.org/blink/trunk@170690 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent eaeebfe6
......@@ -136,7 +136,7 @@ private:
virtual double distanceTo(const AnimatableValue*) const;
friend class KeyframeEffectModel;
template <class Keyframe> friend class KeyframeEffectModel;
};
#define DEFINE_ANIMATABLE_VALUE_TYPE_CASTS(thisType, predicate) \
......
// 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.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));
}
PassOwnPtr<Keyframe::PropertySpecificKeyframe> AnimatableValueKeyframe::createPropertySpecificKeyframe(CSSPropertyID property) const
{
return adoptPtr(new PropertySpecificKeyframe(offset(), easing(), propertyValue(property), composite()));
}
AnimatableValueKeyframe::PropertySpecificKeyframe::PropertySpecificKeyframe(double offset, PassRefPtr<TimingFunction> easing, const AnimatableValue* value, AnimationEffect::CompositeOperation op)
: Keyframe::PropertySpecificKeyframe(offset, easing, op)
, m_value(PassRefPtr<AnimatableValue>(const_cast<AnimatableValue*>(value)))
{ }
AnimatableValueKeyframe::PropertySpecificKeyframe::PropertySpecificKeyframe(double offset, PassRefPtr<TimingFunction> easing, PassRefPtr<AnimatableValue> value)
: Keyframe::PropertySpecificKeyframe(offset, easing, AnimationEffect::CompositeReplace)
, m_value(value)
{
ASSERT(!isNull(m_offset));
}
PassOwnPtr<Keyframe::PropertySpecificKeyframe> AnimatableValueKeyframe::PropertySpecificKeyframe::cloneWithOffset(double offset) const
{
Keyframe::PropertySpecificKeyframe* theClone = new PropertySpecificKeyframe(offset, m_easing, m_value);
return adoptPtr(theClone);
}
PassRefPtr<Interpolation> AnimatableValueKeyframe::PropertySpecificKeyframe::createInterpolation(CSSPropertyID property, Keyframe::PropertySpecificKeyframe* end) const
{
AnimatableValuePropertySpecificKeyframe* to = toAnimatableValuePropertySpecificKeyframe(end);
return LegacyStyleInterpolation::create(value(), to->value(), property);
}
PassOwnPtr<Keyframe::PropertySpecificKeyframe> AnimatableValueKeyframe::PropertySpecificKeyframe::neutralKeyframe(double offset, PassRefPtr<TimingFunction> easing) const
{
return adoptPtr(new AnimatableValueKeyframe::PropertySpecificKeyframe(offset, easing, AnimatableValue::neutralValue(), AnimationEffect::CompositeAdd));
}
}
// 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 PassRefPtr<AnimatableValueKeyframe> create() { return adoptRef(new AnimatableValueKeyframe); }
void setPropertyValue(CSSPropertyID property, PassRefPtr<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;
class PropertySpecificKeyframe : public Keyframe::PropertySpecificKeyframe {
public:
PropertySpecificKeyframe(double offset, PassRefPtr<TimingFunction> easing, const AnimatableValue*, AnimationEffect::CompositeOperation);
AnimatableValue* value() const { return m_value.get(); }
virtual PassOwnPtr<Keyframe::PropertySpecificKeyframe> neutralKeyframe(double offset, PassRefPtr<TimingFunction> easing) const OVERRIDE FINAL;
virtual PassRefPtr<Interpolation> createInterpolation(CSSPropertyID, WebCore::Keyframe::PropertySpecificKeyframe* end) const OVERRIDE FINAL;
private:
PropertySpecificKeyframe(double offset, PassRefPtr<TimingFunction> easing, PassRefPtr<AnimatableValue>);
virtual PassOwnPtr<Keyframe::PropertySpecificKeyframe> cloneWithOffset(double offset) const OVERRIDE;
virtual bool isAnimatableValuePropertySpecificKeyframe() const OVERRIDE { return true; }
RefPtr<AnimatableValue> m_value;
};
private:
AnimatableValueKeyframe()
{ }
AnimatableValueKeyframe(const AnimatableValueKeyframe& copyFrom);
virtual PassRefPtrWillBeRawPtr<Keyframe> clone() const OVERRIDE;
virtual PassOwnPtr<Keyframe::PropertySpecificKeyframe> createPropertySpecificKeyframe(CSSPropertyID) const OVERRIDE;
virtual bool isAnimatableValueKeyframe() const OVERRIDE { return true; }
typedef HashMap<CSSPropertyID, RefPtr<AnimatableValue> > PropertyValueMap;
PropertyValueMap m_propertyValues;
};
typedef AnimatableValueKeyframe::PropertySpecificKeyframe AnimatableValuePropertySpecificKeyframe;
DEFINE_TYPE_CASTS(AnimatableValueKeyframe, Keyframe, value, value->isAnimatableValueKeyframe(), value.isAnimatableValueKeyframe());
DEFINE_TYPE_CASTS(AnimatableValuePropertySpecificKeyframe, PropertySpecificKeyframe, value, value->isAnimatableValuePropertySpecificKeyframe(), value.isAnimatableValuePropertySpecificKeyframe());
}
#endif
......@@ -37,14 +37,14 @@ protected:
PassRefPtrWillBeRawPtr<AnimationEffect> makeAnimationEffect(CSSPropertyID id, PassRefPtrWillBeRawPtr<AnimatableValue> value)
{
KeyframeEffectModel::KeyframeVector keyframes(2);
keyframes[0] = Keyframe::create();
AnimatableValueKeyframeVector keyframes(2);
keyframes[0] = AnimatableValueKeyframe::create();
keyframes[0]->setOffset(0.0);
keyframes[0]->setPropertyValue(id, value.get());
keyframes[1] = Keyframe::create();
keyframes[1] = AnimatableValueKeyframe::create();
keyframes[1]->setOffset(1.0);
keyframes[1]->setPropertyValue(id, value.get());
return KeyframeEffectModel::create(keyframes);
return AnimatableValueKeyframeEffectModel::create(keyframes);
}
PassRefPtr<InertAnimation> makeInertAnimation(PassRefPtrWillBeRawPtr<AnimationEffect> effect)
......@@ -63,7 +63,7 @@ protected:
AnimatableValue* interpolationValue(Interpolation* interpolation)
{
return toLegacyStyleInterpolation(interpolation)->currentValue();
return toLegacyStyleInterpolation(interpolation)->currentValue().get();
}
RefPtr<Document> document;
......
......@@ -88,14 +88,13 @@ TEST_F(AnimationAnimationV8Test, CanCreateAnAnimation)
Element* target = animation->target();
EXPECT_EQ(*element.get(), *target);
const KeyframeEffectModel::KeyframeVector keyframes =
toKeyframeEffectModel(animation->effect())->getFrames();
const KeyframeVector keyframes = toKeyframeEffectModelBase(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);
const AnimatableValue* keyframe1Width = toAnimatableValueKeyframe(keyframes[0].get())->propertyValue(CSSPropertyWidth);
const AnimatableValue* keyframe2Width = toAnimatableValueKeyframe(keyframes[1].get())->propertyValue(CSSPropertyWidth);
ASSERT(keyframe1Width);
ASSERT(keyframe2Width);
......
......@@ -58,10 +58,10 @@ namespace WebCore {
namespace {
void getKeyframeValuesForProperty(const KeyframeEffectModel* 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--;) {
......@@ -131,10 +131,10 @@ PassRefPtr<TimingFunction> CompositorAnimationsTimingFunctionReverser::reverse(c
bool CompositorAnimations::isCandidateForAnimationOnCompositor(const Timing& timing, const AnimationEffect& effect)
{
const KeyframeEffectModel& keyframeEffect = *toKeyframeEffectModel(&effect);
const AnimatableValueKeyframeEffectModel& keyframeEffect = *toAnimatableValueKeyframeEffectModel(&effect);
// Are the keyframes convertible?
const KeyframeEffectModel::KeyframeVector frames = keyframeEffect.getFrames();
const 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)
......@@ -146,16 +146,18 @@ bool CompositorAnimations::isCandidateForAnimationOnCompositor(const Timing& tim
if (properties.isEmpty())
return false;
AnimatableValueKeyframe* frame = toAnimatableValueKeyframe(frames[i].get());
for (PropertySet::const_iterator it = properties.begin(); it != properties.end(); ++it) {
switch (*it) {
case CSSPropertyOpacity:
continue;
case CSSPropertyTransform:
if (toAnimatableTransform(frames[i]->propertyValue(CSSPropertyTransform))->transformOperations().dependsOnBoxSize())
if (toAnimatableTransform(frame->propertyValue(CSSPropertyTransform))->transformOperations().dependsOnBoxSize())
return false;
continue;
case CSSPropertyWebkitFilter: {
const FilterOperations& operations = toAnimatableFilterOperations(frames[i]->propertyValue(CSSPropertyWebkitFilter))->operations();
const FilterOperations& operations = toAnimatableFilterOperations(frame->propertyValue(CSSPropertyWebkitFilter))->operations();
if (operations.hasFilterThatMovesPixels())
return false;
for (size_t i = 0; i < operations.size(); i++) {
......@@ -201,8 +203,8 @@ bool CompositorAnimations::isCandidateForAnimationOnCompositor(const Timing& tim
return false;
// Search for any segments with StepsFunction.
WillBeHeapVector<RefPtrWillBeMember<Keyframe> >::const_iterator end = keyframeEffect.getFrames().end() - 1; // Ignore timing function of last frame.
for (WillBeHeapVector<RefPtrWillBeMember<Keyframe> >::const_iterator iter = keyframeEffect.getFrames().begin(); iter != end; ++iter) {
WillBeHeapVector<RefPtrWillBeMember<Keyframe> >::const_iterator end = frames.end() - 1; // Ignore timing function of last frame.
for (WillBeHeapVector<RefPtrWillBeMember<Keyframe> >::const_iterator iter = frames.begin(); iter != end; ++iter) {
RELEASE_ASSERT((*iter)->easing());
switch ((*iter)->easing()->type()) {
case TimingFunction::LinearFunction:
......@@ -231,7 +233,7 @@ bool CompositorAnimations::startAnimationOnCompositor(const Element& element, co
ASSERT(isCandidateForAnimationOnCompositor(timing, effect));
ASSERT(canStartAnimationOnCompositor(element));
const KeyframeEffectModel& keyframeEffect = *toKeyframeEffectModel(&effect);
const AnimatableValueKeyframeEffectModel& keyframeEffect = *toAnimatableValueKeyframeEffectModel(&effect);
RenderLayer* layer = toRenderBoxModelObject(element.renderer())->layer();
ASSERT(layer);
......@@ -391,7 +393,7 @@ void addKeyframeWithTimingFunction(PlatformAnimationCurveType& curve, const Plat
} // namespace anoymous
void CompositorAnimationsImpl::addKeyframesToCurve(blink::WebAnimationCurve& curve, const KeyframeVector& keyframes, bool reverse)
void CompositorAnimationsImpl::addKeyframesToCurve(blink::WebAnimationCurve& curve, const PropertySpecificKeyframeVector& keyframes, bool reverse)
{
for (size_t i = 0; i < keyframes.size(); i++) {
RefPtr<TimingFunction> reversedTimingFunction;
......@@ -405,7 +407,7 @@ void CompositorAnimationsImpl::addKeyframesToCurve(blink::WebAnimationCurve& cur
}
}
const AnimatableValue* value = keyframes[i]->value();
const AnimatableValue* value = toAnimatableValuePropertySpecificKeyframe(keyframes[i].get())->value();
switch (curve.type()) {
case blink::WebAnimationCurve::AnimationCurveTypeFilter: {
......@@ -439,7 +441,7 @@ void CompositorAnimationsImpl::addKeyframesToCurve(blink::WebAnimationCurve& cur
}
}
void CompositorAnimationsImpl::getAnimationOnCompositor(const Timing& timing, const KeyframeEffectModel& effect, Vector<OwnPtr<blink::WebAnimation> >& animations)
void CompositorAnimationsImpl::getAnimationOnCompositor(const Timing& timing, const AnimatableValueKeyframeEffectModel& effect, Vector<OwnPtr<blink::WebAnimation> >& animations)
{
ASSERT(animations.isEmpty());
CompositorTiming compositorTiming;
......@@ -454,7 +456,7 @@ void CompositorAnimationsImpl::getAnimationOnCompositor(const Timing& timing, co
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;
......
......@@ -36,8 +36,6 @@
namespace WebCore {
typedef KeyframeEffectModel::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 KeyframeEffectModel&, Vector<OwnPtr<blink::WebAnimation> >& animations);
static void getAnimationOnCompositor(const Timing&, const AnimatableValueKeyframeEffectModel&, Vector<OwnPtr<blink::WebAnimation> >& animations);
static void addKeyframesToCurve(blink::WebAnimationCurve&, const KeyframeVector&, bool reverse);
static void addKeyframesToCurve(blink::WebAnimationCurve&, const AnimatableValuePropertySpecificKeyframeVector&, bool reverse);
friend class CompositorAnimations;
friend class AnimationCompositorAnimationsTest;
......
......@@ -132,7 +132,7 @@ TEST_F(AnimationDocumentTimelineTest, HasStarted)
TEST_F(AnimationDocumentTimelineTest, EmptyKeyframeAnimation)
{
RefPtrWillBeRawPtr<KeyframeEffectModel> effect = KeyframeEffectModel::create(KeyframeEffectModel::KeyframeVector());
RefPtrWillBeRawPtr<AnimatableValueKeyframeEffectModel> effect = AnimatableValueKeyframeEffectModel::create(AnimatableValueKeyframeVector());
RefPtr<Animation> anim = Animation::create(element.get(), effect, timing);
timeline->play(anim.get());
......@@ -149,7 +149,7 @@ TEST_F(AnimationDocumentTimelineTest, EmptyKeyframeAnimation)
TEST_F(AnimationDocumentTimelineTest, EmptyForwardsKeyframeAnimation)
{
RefPtrWillBeRawPtr<KeyframeEffectModel> effect = KeyframeEffectModel::create(KeyframeEffectModel::KeyframeVector());
RefPtrWillBeRawPtr<AnimatableValueKeyframeEffectModel> effect = AnimatableValueKeyframeEffectModel::create(AnimatableValueKeyframeVector());
timing.fillMode = Timing::FillModeForwards;
RefPtr<Animation> anim = Animation::create(element.get(), effect, timing);
......@@ -193,8 +193,8 @@ TEST_F(AnimationDocumentTimelineTest, PauseForTesting)
{
float seekTime = 1;
timing.fillMode = Timing::FillModeForwards;
RefPtr<Animation> anim1 = Animation::create(element.get(), KeyframeEffectModel::create(KeyframeEffectModel::KeyframeVector()), timing);
RefPtr<Animation> anim2 = Animation::create(element.get(), KeyframeEffectModel::create(KeyframeEffectModel::KeyframeVector()), timing);
RefPtr<Animation> anim1 = Animation::create(element.get(), AnimatableValueKeyframeEffectModel::create(AnimatableValueKeyframeVector()), timing);
RefPtr<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);
......@@ -226,11 +226,11 @@ TEST_F(AnimationDocumentTimelineTest, NumberOfActiveAnimations)
Timing timingAutoFill;
timingAutoFill.iterationDuration = 2;
RefPtr<Animation> anim1 = Animation::create(element.get(), KeyframeEffectModel::create(KeyframeEffectModel::KeyframeVector()), timingForwardFill);
RefPtr<Animation> anim2 = Animation::create(element.get(), KeyframeEffectModel::create(KeyframeEffectModel::KeyframeVector()), timingNoFill);
RefPtr<Animation> anim3 = Animation::create(element.get(), KeyframeEffectModel::create(KeyframeEffectModel::KeyframeVector()), timingBackwardFillDelay);
RefPtr<Animation> anim4 = Animation::create(element.get(), KeyframeEffectModel::create(KeyframeEffectModel::KeyframeVector()), timingNoFillDelay);
RefPtr<Animation> anim5 = Animation::create(element.get(), KeyframeEffectModel::create(KeyframeEffectModel::KeyframeVector()), timingAutoFill);
RefPtr<Animation> anim1 = Animation::create(element.get(), AnimatableValueKeyframeEffectModel::create(AnimatableValueKeyframeVector()), timingForwardFill);
RefPtr<Animation> anim2 = Animation::create(element.get(), AnimatableValueKeyframeEffectModel::create(AnimatableValueKeyframeVector()), timingNoFill);
RefPtr<Animation> anim3 = Animation::create(element.get(), AnimatableValueKeyframeEffectModel::create(AnimatableValueKeyframeVector()), timingBackwardFillDelay);
RefPtr<Animation> anim4 = Animation::create(element.get(), AnimatableValueKeyframeEffectModel::create(AnimatableValueKeyframeVector()), timingNoFillDelay);
RefPtr<Animation> anim5 = Animation::create(element.get(), AnimatableValueKeyframeEffectModel::create(AnimatableValueKeyframeVector()), timingAutoFill);
timeline->play(anim1.get());
timeline->play(anim2.get());
......
......@@ -58,14 +58,14 @@ PassRefPtrWillBeRawPtr<AnimationEffect> EffectInput::convert(Element* element, c
StyleSheetContents* styleSheetContents = element->document().elementSheet().contents();
// FIXME: Move this code into KeyframeEffectModel, it will be used by the IDL constructor for that class.
KeyframeEffectModel::KeyframeVector keyframes;
AnimatableValueKeyframeVector keyframes;
WillBeHeapVector<RefPtrWillBeMember<MutableStylePropertySet> > propertySetVector;
for (size_t i = 0; i < keyframeDictionaryVector.size(); ++i) {
RefPtrWillBeRawPtr<MutableStylePropertySet> propertySet = MutableStylePropertySet::create();
propertySetVector.append(propertySet);
RefPtrWillBeRawPtr<Keyframe> keyframe = Keyframe::create();
RefPtrWillBeRawPtr<AnimatableValueKeyframe> keyframe = AnimatableValueKeyframe::create();
keyframes.append(keyframe);
double offset;
......@@ -106,7 +106,7 @@ PassRefPtrWillBeRawPtr<AnimationEffect> EffectInput::convert(Element* element, c
}
// FIXME: Replace this with code that just parses, when that code is available.
RefPtrWillBeRawPtr<KeyframeEffectModel> keyframeEffectModel = StyleResolver::createKeyframeEffectModel(*element, propertySetVector, keyframes);
RefPtrWillBeRawPtr<AnimatableValueKeyframeEffectModel> keyframeEffectModel = StyleResolver::createKeyframeEffectModel(*element, propertySetVector, keyframes);
if (!keyframeEffectModel->isReplaceOnly()) {
exceptionState.throwDOMException(NotSupportedError, "Partial keyframes are not supported.");
return nullptr;
......
......@@ -5,6 +5,7 @@
#include "config.h"
#include "core/animation/Interpolation.h"
#include "core/animation/AnimatableDouble.h"
#include "core/css/resolver/AnimatedStyleBuilder.h"
#include "core/css/resolver/StyleResolverState.h"
......@@ -70,8 +71,7 @@ void StyleInterpolation::trace(Visitor* visitor)
void LegacyStyleInterpolation::apply(StyleResolverState& state) const
{
AnimatableValue* value = currentValue();
AnimatedStyleBuilder::applyProperty(m_id, state, value);
AnimatedStyleBuilder::applyProperty(m_id, state, currentValue().get());
}
void LegacyStyleInterpolation::trace(Visitor* visitor)
......
......@@ -44,7 +44,6 @@ private:
friend class AnimationInterpolableValueTest;
friend class AnimationInterpolationEffectTest;
};
class StyleInterpolation : public Interpolation {
......@@ -83,7 +82,7 @@ public:
virtual void apply(StyleResolverState&) const;
virtual bool isLegacyStyleInterpolation() const OVERRIDE FINAL { return true; }
AnimatableValue* currentValue() const
PassRefPtr<AnimatableValue> currentValue() const
{
InterpolableAnimatableValue* value = static_cast<InterpolableAnimatableValue*>(m_cachedValue.get());
return value->value();
......
// 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 "CSSPropertyNames.h"
#include "core/animation/AnimationEffect.h"
#include "core/animation/TimedItem.h"
namespace WebCore {
typedef HashSet<CSSPropertyID> PropertySet;
// 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 RefPtrWillBeRawPtr<Keyframe>&, const RefPtrWillBeRawPtr<Keyframe>&);
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; }
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 PassOwnPtr<PropertySpecificKeyframe> cloneWithOffset(double offset) const = 0;
virtual bool isAnimatableValuePropertySpecificKeyframe() const { return false; }
virtual bool isStringPropertySpecificKeyframe() const { return false; }
virtual PassOwnPtr<PropertySpecificKeyframe> neutralKeyframe(double offset, PassRefPtr<TimingFunction> easing) const = 0;
virtual PassRefPtr<Interpolation> createInterpolation(CSSPropertyID, WebCore::Keyframe::PropertySpecificKeyframe* end) const = 0;
protected:
PropertySpecificKeyframe(double offset, PassRefPtr<TimingFunction> easing, AnimationEffect::CompositeOperation);
double m_offset;
RefPtr<TimingFunction> m_easing;
AnimationEffect::CompositeOperation m_composite;
};
virtual PassOwnPtr<PropertySpecificKeyframe> createPropertySpecificKeyframe(CSSPropertyID) const = 0;
protected:
Keyframe()
: m_offset(nullValue())
, m_composite(AnimationEffect::CompositeReplace)
, m_easing(LinearTimingFunction::preset())
{
}
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;
};
typedef Keyframe::PropertySpecificKeyframe PropertySpecificKeyframe;
}
#endif
......@@ -36,72 +36,12 @@
namespace WebCore {
Keyframe::Keyframe()
: m_offset(nullValue())
, m_composite(AnimationEffect::CompositeReplace)
, m_easing(LinearTimingFunction::preset())
{ }
Keyframe::Keyframe(const Keyframe& copyFrom)
: m_offset(copyFrom.m_offset)
, m_composite(copyFrom.m_composite)
, m_easing(copyFrom.m_easing)
bool Keyframe::compareOffsets(const RefPtrWillBeRawPtr<Keyframe>& a, const RefPtrWillBeRawPtr<Keyframe>& b)
{
ASSERT(m_easing);
for (PropertyValueMap::const_iterator iter = copyFrom.m_propertyValues.begin(); iter != copyFrom.m_propertyValues.end(); ++iter)
setPropertyValue(iter->key, iter->value.get());
return a->offset() < b->offset();
}
void Keyframe::setEasing(PassRefPtr<TimingFunction> easing)
{
ASSERT(easing);
m_easing = easing;
}
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;
}
PassRefPtrWillBeRawPtr<Keyframe> Keyframe::cloneWithOffset(double offset) const
{
RefPtrWillBeRawPtr<Keyframe> theClone = clone();
theClone->setOffset(offset);
return theClone.release();
}
void Keyframe::trace(Visitor* visitor)
{
visitor->trace(m_propertyValues);
}
KeyframeEffectModel::KeyframeEffectModel(const KeyframeVector& keyframes)
: m_keyframes(keyframes)
{
}
PropertySet KeyframeEffectModel::properties() const
PropertySet KeyframeEffectModelBase::properties() const
{
PropertySet result;
if (!m_keyframes.size()) {
......@@ -117,7 +57,7 @@ PropertySet KeyframeEffectModel::properties() const
return result;
}
PassOwnPtrWillBeRawPtr<WillBeHeapVector<RefPtrWillBeMember<Interpolation> > > KeyframeEffectModel::sample(int iteration, double fraction, double iterationDuration) const
PassOwnPtrWillBeRawPtr<WillBeHeapVector<RefPtrWillBeMember<Interpolation> > > KeyframeEffectModelBase::sample(int iteration, double fraction, double iterationDuration) const
{
ASSERT(iteration >= 0);
ASSERT(!isNull(fraction));
......@@ -127,7 +67,7 @@ PassOwnPtrWillBeRawPtr<WillBeHeapVector<RefPtrWillBeMember<Interpolation> > > Ke
return m_interpolationEffect->getActiveInterpolations(fraction, iterationDuration);
}
KeyframeEffectModel::KeyframeVector KeyframeEffectModel::normalizedKeyframes(const KeyframeVector& keyframes)
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].
......@@ -191,7 +131,8 @@ KeyframeEffectModel::KeyframeVector KeyframeEffectModel::normalizedKeyframes(con
return result;
}
void KeyframeEffectModel::ensureKeyframeGroups() const
void KeyframeEffectModelBase::ensureKeyframeGroups() const
{
if (m_keyframeGroups)
return;
......@@ -211,19 +152,18 @@ void KeyframeEffectModel::ensureKeyframeGroups() const
group = groupIter->value.get();
ASSERT(keyframe->composite() == AnimationEffect::CompositeReplace);
group->appendKeyframe(adoptPtrWillBeNoop(
new PropertySpecificKeyframe(keyframe->offset(), keyframe->easing(), keyframe->propertyValue(property), keyframe->composite())));
group->appendKeyframe(keyframe->createPropertySpecificKeyframe(property));
}
}
// Add synthetic keyframes.
for (KeyframeGroupMap::iterator iter = m_keyframeGroups->begin(); iter != m_keyframeGroups->end(); ++iter) {
iter->value->addSyntheticKeyframeIfRequired();
iter->value->addSyntheticKeyframeIfRequired(this);
iter->value->removeRedundantKeyframes();
}
}
void KeyframeEffectModel::ensureInterpolationEffect() const
void KeyframeEffectModelBase::ensureInterpolationEffect() const
{
if (m_interpolationEffect)
return;
......@@ -232,26 +172,20 @@ void KeyframeEffectModel::ensureInterpolationEffect() const
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);
const AnimatableValue* start;
const AnimatableValue* end = keyframes[0]->value();
for (size_t i = 0; i < keyframes.size() - 1; i++) {
ASSERT(keyframes[i + 1]->composite() == AnimationEffect::CompositeReplace);
start = end;
end = keyframes[i + 1]->value();
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(
LegacyStyleInterpolation::create(
AnimatableValue::takeConstRef(start),
AnimatableValue::takeConstRef(end), iter->key),
m_interpolationEffect->addInterpolation(keyframes[i]->createInterpolation(iter->key, keyframes[i + 1].get()),
keyframes[i]->easing(), keyframes[i]->offset(), keyframes[i + 1]->offset(), applyFrom, applyTo);
}
}
}
bool KeyframeEffectModel::isReplaceOnly()
bool KeyframeEffectModelBase::isReplaceOnly()
{
ensureKeyframeGroups();
for (KeyframeGroupMap::iterator iter = m_keyframeGroups->begin(); iter != m_keyframeGroups->end(); ++iter) {
......@@ -264,7 +198,7 @@ bool KeyframeEffectModel::isReplaceOnly()
return true;
}
void KeyframeEffectModel::trace(Visitor* visitor)
void KeyframeEffectModelBase::trace(Visitor* visitor)
{
visitor->trace(m_keyframes);
visitor->trace(m_interpolationEffect);
......@@ -273,40 +207,20 @@ void KeyframeEffectModel::trace(Visitor* visitor)
#endif
}
KeyframeEffectModel::PropertySpecificKeyframe::PropertySpecificKeyframe(double offset, PassRefPtr<TimingFunction> easing, const AnimatableValue* value, CompositeOperation composite)
: m_offset(offset)
, m_easing(easing)
, m_composite(composite)
{
m_value = AnimatableValue::takeConstRef(value);
}
KeyframeEffectModel::PropertySpecificKeyframe::PropertySpecificKeyframe(double offset, PassRefPtr<TimingFunction> easing, PassRefPtrWillBeRawPtr<AnimatableValue> value, CompositeOperation composite)
Keyframe::PropertySpecificKeyframe::PropertySpecificKeyframe(double offset, PassRefPtr<TimingFunction> easing, AnimationEffect::CompositeOperation composite)
: m_offset(offset)
, m_easing(easing)
, m_value(value)
, m_composite(composite)
{
ASSERT(!isNull(m_offset));
}
PassOwnPtrWillBeRawPtr<KeyframeEffectModel::PropertySpecificKeyframe> KeyframeEffectModel::PropertySpecificKeyframe::cloneWithOffset(double offset) const
{
return adoptPtrWillBeNoop(new PropertySpecificKeyframe(offset, m_easing, m_value.get(), m_composite));
}
void KeyframeEffectModel::PropertySpecificKeyframe::trace(Visitor* visitor)
{
visitor->trace(m_value);
}
void KeyframeEffectModel::PropertySpecificKeyframeGroup::appendKeyframe(PassOwnPtrWillBeRawPtr<PropertySpecificKeyframe> keyframe)
void KeyframeEffectModelBase::PropertySpecificKeyframeGroup::appendKeyframe(PassOwnPtr<PropertySpecificKeyframe> keyframe)
{
ASSERT(m_keyframes.isEmpty() || m_keyframes.last()->offset() <= keyframe->offset());
m_keyframes.append(keyframe);
}
void KeyframeEffectModel::PropertySpecificKeyframeGroup::removeRedundantKeyframes()
void KeyframeEffectModelBase::PropertySpecificKeyframeGroup::removeRedundantKeyframes()
{
// As an optimization, removes keyframes in the following categories, as
// they will never be used by sample().
......@@ -325,20 +239,26 @@ void KeyframeEffectModel::PropertySpecificKeyframeGroup::removeRedundantKeyframe
ASSERT(m_keyframes.size() >= 2);
}
void KeyframeEffectModel::PropertySpecificKeyframeGroup::addSyntheticKeyframeIfRequired()
void KeyframeEffectModelBase::PropertySpecificKeyframeGroup::addSyntheticKeyframeIfRequired(const KeyframeEffectModelBase* context)
{
ASSERT(!m_keyframes.isEmpty());
if (m_keyframes.first()->offset() != 0.0)
m_keyframes.insert(0, adoptPtrWillBeNoop(new PropertySpecificKeyframe(0, nullptr, AnimatableValue::neutralValue(), CompositeAdd)));
m_keyframes.insert(0, m_keyframes.first()->neutralKeyframe(0, nullptr));
if (m_keyframes.last()->offset() != 1.0)
appendKeyframe(adoptPtrWillBeNoop(new PropertySpecificKeyframe(1, nullptr, AnimatableValue::neutralValue(), CompositeAdd)));
appendKeyframe(m_keyframes.last()->neutralKeyframe(1, nullptr));
}
void KeyframeEffectModel::PropertySpecificKeyframeGroup::trace(Visitor* visitor)
void KeyframeEffectModelBase::PropertySpecificKeyframeGroup::trace(Visitor* visitor)
{
#if ENABLE_OILPAN
#if ENABLE(OILPAN)
visitor->trace(m_keyframes);
#endif
}
template <>
bool KeyframeEffectModel<AnimatableValueKeyframe>::isAnimatableValueKeyframeEffectModel() const { return true; }
template <>
bool KeyframeEffectModel<StringKeyframe>::isStringKeyframeEffectModel() const { return true; }
} // namespace
......@@ -31,9 +31,11 @@
#ifndef KeyframeEffectModel_h
#define KeyframeEffectModel_h
#include "core/animation/AnimatableValue.h"
#include "core/animation/AnimatableValueKeyframe.h"
#include "core/animation/AnimationEffect.h"
#include "core/animation/InterpolationEffect.h"
#include "core/animation/StringKeyframe.h"
#include "core/animation/TimedItem.h"
#include "heap/Handle.h"
#include "platform/animation/TimingFunction.h"
#include "wtf/HashMap.h"
......@@ -45,121 +47,54 @@
namespace WebCore {
typedef HashSet<CSSPropertyID> PropertySet;
class KeyframeEffectModelTest;
// Represents the keyframes set through the API.
class Keyframe : public RefCountedWillBeGarbageCollectedFinalized<Keyframe> {
public:
static PassRefPtrWillBeRawPtr<Keyframe> create()
{
return adoptRefWillBeNoop(new Keyframe);
}
static bool compareOffsets(const RefPtrWillBeRawPtr<Keyframe>& a, const RefPtrWillBeRawPtr<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 setEasing(PassRefPtr<TimingFunction>);
TimingFunction* easing() const { return m_easing.get(); }
void setPropertyValue(CSSPropertyID, const AnimatableValue*);
void clearPropertyValue(CSSPropertyID);
const AnimatableValue* propertyValue(CSSPropertyID) const;
PropertySet properties() const;
PassRefPtrWillBeRawPtr<Keyframe> clone() const { return adoptRefWillBeNoop(new Keyframe(*this)); }
PassRefPtrWillBeRawPtr<Keyframe> cloneWithOffset(double offset) const;
void trace(Visitor*);
private:
Keyframe();
Keyframe(const Keyframe&);
double m_offset;
AnimationEffect::CompositeOperation m_composite;
RefPtr<TimingFunction> m_easing;
typedef WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<AnimatableValue> > PropertyValueMap;
PropertyValueMap m_propertyValues;
};
class KeyframeEffectModel FINAL : public AnimationEffect {
class KeyframeEffectModelBase : public AnimationEffect {
public:
class PropertySpecificKeyframe;
typedef WillBeHeapVector<RefPtrWillBeMember<Keyframe> > KeyframeVector;
typedef WillBeHeapVector<OwnPtrWillBeMember<PropertySpecificKeyframe> > PropertySpecificKeyframeVector;
// FIXME: Implement accumulation.
static PassRefPtrWillBeRawPtr<KeyframeEffectModel> create(const KeyframeVector& keyframes)
{
return adoptRefWillBeNoop(new KeyframeEffectModel(keyframes));
}
virtual bool affects(CSSPropertyID property) OVERRIDE
{
ensureKeyframeGroups();
return m_keyframeGroups->contains(property);
}
// AnimationEffect implementation.
virtual PassOwnPtrWillBeRawPtr<WillBeHeapVector<RefPtrWillBeMember<Interpolation> > > sample(int iteration, double fraction, double iterationDuration) const OVERRIDE;
// FIXME: Implement setFrames()
const KeyframeVector& getFrames() const { return m_keyframes; }
virtual bool isKeyframeEffectModel() const OVERRIDE { return true; }
bool isReplaceOnly();
PropertySet properties() const;
class PropertySpecificKeyframe : public NoBaseWillBeGarbageCollectedFinalized<PropertySpecificKeyframe> {
public:
PropertySpecificKeyframe(double offset, PassRefPtr<TimingFunction> easing, const AnimatableValue*, CompositeOperation);
double offset() const { return m_offset; }
TimingFunction* easing() const { return m_easing.get(); }
const AnimatableValue* value() const { return m_value.get(); }
AnimationEffect::CompositeOperation composite() const { return m_composite; }
PassOwnPtrWillBeRawPtr<PropertySpecificKeyframe> cloneWithOffset(double offset) const;
void trace(Visitor*);
private:
// Used by cloneWithOffset().
PropertySpecificKeyframe(double offset, PassRefPtr<TimingFunction> easing, PassRefPtrWillBeRawPtr<AnimatableValue>, CompositeOperation);
double m_offset;
RefPtr<TimingFunction> m_easing;
RefPtrWillBeMember<AnimatableValue> m_value;
AnimationEffect::CompositeOperation m_composite;
};
class PropertySpecificKeyframeGroup : public NoBaseWillBeGarbageCollectedFinalized<PropertySpecificKeyframeGroup> {
typedef Vector<OwnPtr<Keyframe::PropertySpecificKeyframe> > PropertySpecificKeyframeVector;
class PropertySpecificKeyframeGroup {
public:
void appendKeyframe(PassOwnPtrWillBeRawPtr<PropertySpecificKeyframe>);
void appendKeyframe(PassOwnPtrWillBeRawPtr<Keyframe::PropertySpecificKeyframe>);
const PropertySpecificKeyframeVector& keyframes() const { return m_keyframes; }
void trace(Visitor*);
private:
PropertySpecificKeyframeVector m_keyframes;
void removeRedundantKeyframes();
void addSyntheticKeyframeIfRequired();
void addSyntheticKeyframeIfRequired(const KeyframeEffectModelBase* context);
friend class KeyframeEffectModel;
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();
}
virtual void trace(Visitor*) OVERRIDE;
// AnimationEffect implementation.
virtual PassOwnPtrWillBeRawPtr<WillBeHeapVector<RefPtrWillBeMember<Interpolation> > > sample(int iteration, double fraction, double iterationDuration) const OVERRIDE;
private:
KeyframeEffectModel(const KeyframeVector& keyframes);
virtual bool isKeyframeEffectModel() const OVERRIDE { return true; }
virtual bool isAnimatableValueKeyframeEffectModel() const { return false; }
virtual bool isStringKeyframeEffectModel() const { return false; }
virtual void trace(Visitor*) OVERRIDE;
protected:
static KeyframeVector normalizedKeyframes(const KeyframeVector& keyframes);
// Lazily computes the groups of property-specific keyframes.
......@@ -172,13 +107,57 @@ private:
// property-specific lists.
typedef WillBeHeapHashMap<CSSPropertyID, OwnPtrWillBeMember<PropertySpecificKeyframeGroup> > KeyframeGroupMap;
mutable OwnPtrWillBeMember<KeyframeGroupMap> m_keyframeGroups;
mutable RefPtrWillBeMember<InterpolationEffect> m_interpolationEffect;
mutable RefPtr<InterpolationEffect> m_interpolationEffect;
friend class KeyframeEffectModelTest;
bool affects(CSSPropertyID property)
{
ensureKeyframeGroups();
return m_keyframeGroups->contains(property);
}
};
DEFINE_TYPE_CASTS(KeyframeEffectModel, AnimationEffect, value, value->isKeyframeEffectModel(), value.isKeyframeEffectModel());
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));
}
} // namespace WebCore
......
// 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"
namespace WebCore {
StringKeyframe::StringKeyframe(const StringKeyframe& copyFrom)
: Keyframe(copyFrom.m_offset, copyFrom.m_composite, copyFrom.m_easing)
{
for (typename PropertyValueMap::const_iterator iter = copyFrom.m_propertyValues.begin(); iter != copyFrom.m_propertyValues.end(); ++iter)
setPropertyValue(iter->key, iter->value);
}
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 (typename PropertyValueMap::const_iterator iter = m_propertyValues.begin(); iter != m_propertyValues.end(); ++iter)
properties.add(*iter.keys());
return properties;
}
PassRefPtrWillBeRawPtr<Keyframe> StringKeyframe::clone() const OVERRIDE
{
return adoptRefWillBeNoop(new StringKeyframe(*this));
}
PassOwnPtr<Keyframe::PropertySpecificKeyframe> StringKeyframe::createPropertySpecificKeyframe(CSSPropertyID property) const
{
return adoptPtr(new PropertySpecificKeyframe(offset(), easing(), propertyValue(property), composite()));
}
StringKeyframe::PropertySpecificKeyframe::PropertySpecificKeyframe(double offset, PassRefPtr<TimingFunction> easing, const String& value, AnimationEffect::CompositeOperation op)
: Keyframe::PropertySpecificKeyframe(offset, easing, op)
, m_value(value)
{ }
StringKeyframe::PropertySpecificKeyframe::PropertySpecificKeyframe(double offset, PassRefPtr<TimingFunction> easing, const String& value)
: Keyframe::PropertySpecificKeyframe(offset, easing, AnimationEffect::CompositeReplace)
, m_value(value)
{
ASSERT(!isNull(m_offset));
}
PassRefPtr<Interpolation> StringKeyframe::PropertySpecificKeyframe::createInterpolation(CSSPropertyID property, Keyframe::PropertySpecificKeyframe* end) const
{
ASSERT_UNUSED(end, end);
// FIXME: Convert string keyframe value pairs to interpolations.
return nullptr;
}
PassOwnPtr<Keyframe::PropertySpecificKeyframe> StringKeyframe::PropertySpecificKeyframe::neutralKeyframe(double offset, PassRefPtr<TimingFunction> easing) const
{
return adoptPtr(new StringKeyframe::PropertySpecificKeyframe(offset, easing, emptyString(), AnimationEffect::CompositeAdd));
}
PassOwnPtr<Keyframe::PropertySpecificKeyframe> StringKeyframe::PropertySpecificKeyframe::cloneWithOffset(double offset) const
{
Keyframe::PropertySpecificKeyframe *theClone = new PropertySpecificKeyframe(offset, m_easing, m_value);
return adoptPtr(theClone);
}
}
// 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/AnimatableValue.h"
#include "core/animation/Keyframe.h"
namespace WebCore {
class StringKeyframe : public Keyframe {
public:
static PassRefPtr<StringKeyframe> create() { return adoptRef(new StringKeyframe); }
void setPropertyValue(CSSPropertyID property, const String& value)
{
m_propertyValues.add(property, value);
}
void clearPropertyValue(CSSPropertyID property) { m_propertyValues.remove(property); }
String propertyValue(CSSPropertyID property) const
{
ASSERT(m_propertyValues.contains(property));
return m_propertyValues.get(property);
}
virtual PropertySet properties() const OVERRIDE;
class PropertySpecificKeyframe : public Keyframe::PropertySpecificKeyframe {
public:
PropertySpecificKeyframe(double offset, PassRefPtr<TimingFunction> easing, const String& value, AnimationEffect::CompositeOperation);
const String& value() const { return m_value; }
virtual PassOwnPtr<Keyframe::PropertySpecificKeyframe> neutralKeyframe(double offset, PassRefPtr<TimingFunction> easing) const OVERRIDE FINAL;
virtual PassRefPtr<Interpolation> createInterpolation(CSSPropertyID, WebCore::Keyframe::PropertySpecificKeyframe* end) const OVERRIDE FINAL;
private:
PropertySpecificKeyframe(double offset, PassRefPtr<TimingFunction> easing, const String& value);
virtual PassOwnPtr<Keyframe::PropertySpecificKeyframe> cloneWithOffset(double offset) const;
virtual bool isStringPropertySpecificKeyframe() const OVERRIDE { return true; }
String m_value;
};
private:
StringKeyframe() { }
StringKeyframe(const StringKeyframe& copyFrom);
virtual PassRefPtrWillBeRawPtr<Keyframe> clone() const OVERRIDE;
virtual PassOwnPtr<Keyframe::PropertySpecificKeyframe> createPropertySpecificKeyframe(CSSPropertyID) const OVERRIDE;
virtual bool isStringKeyframe() const OVERRIDE { return true; }
typedef HashMap<CSSPropertyID, String> PropertyValueMap;
PropertyValueMap m_propertyValues;
};
typedef StringKeyframe::PropertySpecificKeyframe StringPropertySpecificKeyframe;
}
#endif
......@@ -97,7 +97,7 @@ CSSPropertyID propertyForAnimation(CSSPropertyID property)
}
static void resolveKeyframes(StyleResolver* resolver, Element* element, const Element& parentElement, const RenderStyle& style, RenderStyle* parentStyle, const AtomicString& name, TimingFunction* defaultTimingFunction,
KeyframeEffectModel::KeyframeVector& keyframes)
AnimatableValueKeyframeVector& keyframes)
{
// When the element is null, use its parent for scoping purposes.
const Element* elementForScoping = element ? element : &parentElement;
......@@ -115,7 +115,7 @@ static void resolveKeyframes(StyleResolver* resolver, Element* element, const El
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);
RefPtrWillBeRawPtr<Keyframe> keyframe = Keyframe::create();
RefPtrWillBeRawPtr<AnimatableValueKeyframe> keyframe = AnimatableValueKeyframe::create();
const Vector<double>& offsets = styleKeyframe->keys();
ASSERT(!offsets.isEmpty());
keyframe->setOffset(offsets[0]);
......@@ -133,7 +133,7 @@ static void resolveKeyframes(StyleResolver* resolver, Element* element, const El
keyframes.append(keyframe);
// The last keyframe specified at a given offset is used.
for (size_t j = 1; j < offsets.size(); ++j) {
keyframes.append(keyframe->cloneWithOffset(offsets[j]));
keyframes.append(toAnimatableValueKeyframe(keyframe->cloneWithOffset(offsets[j]).get()));
}
}
ASSERT(!keyframes.isEmpty());
......@@ -156,15 +156,15 @@ static void resolveKeyframes(StyleResolver* resolver, Element* element, const El
keyframes.shrink(targetIndex + 1);
// Add 0% and 100% keyframes if absent.
RefPtrWillBeRawPtr<Keyframe> startKeyframe = keyframes[0];
RefPtrWillBeRawPtr<AnimatableValueKeyframe> startKeyframe = keyframes[0];
if (startKeyframe->offset()) {
startKeyframe = Keyframe::create();
startKeyframe = AnimatableValueKeyframe::create();
startKeyframe->setOffset(0);
keyframes.prepend(startKeyframe);
}
RefPtrWillBeRawPtr<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);
keyframes.append(endKeyframe);
}
......@@ -341,11 +341,11 @@ void CSSAnimations::calculateAnimationUpdate(CSSAnimationUpdate* update, Element
Timing timing;
bool isPaused;
RefPtr<TimingFunction> keyframeTimingFunction = timingFromAnimationData(animationData, timing, isPaused);
KeyframeEffectModel::KeyframeVector resolvedKeyframes;
AnimatableValueKeyframeVector resolvedKeyframes;
resolveKeyframes(resolver, element, parentElement, style, parentStyle, animationName, keyframeTimingFunction.get(), resolvedKeyframes);
if (!resolvedKeyframes.isEmpty()) {
ASSERT(!activeAnimations || !activeAnimations->isAnimationStyleChange());
update->startAnimation(animationName, InertAnimation::create(KeyframeEffectModel::create(resolvedKeyframes), timing, isPaused));
update->startAnimation(animationName, InertAnimation::create(AnimatableValueKeyframeEffectModel::create(resolvedKeyframes), timing, isPaused));
}
}
}
......@@ -432,16 +432,16 @@ void CSSAnimations::maybeApplyPendingUpdate(Element* element)
double oldStartTime = oldTransition.second;
double inheritedTime = isNull(oldStartTime) ? 0 : element->document().transitionTimeline().currentTime() - oldStartTime;
oldAnimation->updateInheritedTime(inheritedTime);
KeyframeEffectModel* oldEffect = toKeyframeEffectModel(inertAnimation->effect());
const KeyframeEffectModel::KeyframeVector& frames = oldEffect->getFrames();
KeyframeEffectModel::KeyframeVector newFrames;
newFrames.append(frames[0]->clone());
AnimatableValueKeyframeEffectModel* oldEffect = toAnimatableValueKeyframeEffectModel(inertAnimation->effect());
const KeyframeVector& frames = oldEffect->getFrames();
AnimatableValueKeyframeVector newFrames;
newFrames.append(toAnimatableValueKeyframe(frames[0]->clone().get()));
newFrames[0]->clearPropertyValue(id);
ASSERT(oldAnimation->activeInterpolations().size() == 1);
const AnimatableValue* value = toLegacyStyleInterpolation(oldAnimation->activeInterpolations()[0].get())->currentValue();
newFrames[0]->setPropertyValue(id, value);
newFrames.append(frames[1]->clone());
effect = KeyframeEffectModel::create(newFrames);
RefPtr<AnimatableValue> value = toLegacyStyleInterpolation(oldAnimation->activeInterpolations()[0].get())->currentValue();
newFrames[0]->setPropertyValue(id, value.release());
newFrames.append(toAnimatableValueKeyframe(frames[1]->clone().get()));
effect = AnimatableValueKeyframeEffectModel::create(newFrames);
}
RefPtr<Animation> transition = Animation::create(element, effect, inertAnimation->specifiedTiming(), Animation::TransitionPriority, eventDelegate.release());
RefPtr<AnimationPlayer> player = element->document().transitionTimeline().createAnimationPlayer(transition.get());
......@@ -490,20 +490,20 @@ void CSSAnimations::calculateTransitionUpdateForProperty(CSSPropertyID id, const
// Note that the backwards part is required for delay to work.
timing.fillMode = Timing::FillModeBoth;
KeyframeEffectModel::KeyframeVector keyframes;
AnimatableValueKeyframeVector keyframes;
RefPtrWillBeRawPtr<Keyframe> startKeyframe = Keyframe::create();
RefPtrWillBeRawPtr<AnimatableValueKeyframe> startKeyframe = AnimatableValueKeyframe::create();
startKeyframe->setPropertyValue(id, from.get());
startKeyframe->setOffset(0);
startKeyframe->setEasing(timingFunction);
keyframes.append(startKeyframe);
RefPtrWillBeRawPtr<Keyframe> endKeyframe = Keyframe::create();
RefPtrWillBeRawPtr<AnimatableValueKeyframe> endKeyframe = AnimatableValueKeyframe::create();
endKeyframe->setPropertyValue(id, to.get());
endKeyframe->setOffset(1);
keyframes.append(endKeyframe);
RefPtrWillBeRawPtr<KeyframeEffectModel> effect = KeyframeEffectModel::create(keyframes);
RefPtrWillBeRawPtr<AnimatableValueKeyframeEffectModel> effect = AnimatableValueKeyframeEffectModel::create(keyframes);
CSSPropertyID eventId = anim->animationMode() == CSSAnimationData::AnimateAll ? id : anim->property();
update->startTransition(id, eventId, from.get(), to.get(), InertAnimation::create(effect, timing, isPaused));
......
......@@ -611,6 +611,8 @@
'animation/AnimatableUnknown.h',
'animation/AnimatableValue.cpp',
'animation/AnimatableValue.h',
'animation/AnimatableValueKeyframe.cpp',
'animation/AnimatableValueKeyframe.h',
'animation/AnimatableVisibility.cpp',
'animation/AnimatableVisibility.h',
'animation/Animation.cpp',
......@@ -619,6 +621,8 @@
'animation/AnimationClock.h',
'animation/AnimationEffect.h',
'animation/AnimationHelpers.h',
'animation/AnimationPlayer.cpp',
'animation/AnimationPlayer.h',
'animation/AnimationStack.cpp',
'animation/AnimationStack.h',
'animation/AnimationTranslationUtil.cpp',
......@@ -644,8 +648,8 @@
'animation/InterpolationEffect.h',
'animation/KeyframeEffectModel.cpp',
'animation/KeyframeEffectModel.h',
'animation/AnimationPlayer.cpp',
'animation/AnimationPlayer.h',
'animation/StringKeyframe.cp',
'animation/StringKeyframe.h',
'animation/TimedItem.cpp',
'animation/TimedItem.h',
'animation/TimedItemCalculations.h',
......
......@@ -787,7 +787,7 @@ PassRefPtr<RenderStyle> StyleResolver::styleForKeyframe(Element* element, const
// This function is used by the WebAnimations JavaScript API method animate().
// FIXME: Remove this when animate() switches away from resolution-dependent parsing.
PassRefPtrWillBeRawPtr<KeyframeEffectModel> StyleResolver::createKeyframeEffectModel(Element& element, const WillBeHeapVector<RefPtrWillBeMember<MutableStylePropertySet> >& propertySetVector, KeyframeEffectModel::KeyframeVector& keyframes)
PassRefPtrWillBeRawPtr<AnimatableValueKeyframeEffectModel> StyleResolver::createKeyframeEffectModel(Element& element, const WillBeHeapVector<RefPtrWillBeMember<MutableStylePropertySet> >& propertySetVector, AnimatableValueKeyframeVector& keyframes)
{
ASSERT(propertySetVector.size() == keyframes.size());
......@@ -802,8 +802,7 @@ PassRefPtrWillBeRawPtr<KeyframeEffectModel> StyleResolver::createKeyframeEffectM
keyframes[i]->setPropertyValue(id, CSSAnimatableValueFactory::create(id, *state.style()).get());
}
}
return KeyframeEffectModel::create(keyframes);
return AnimatableValueKeyframeEffectModel::create(keyframes);
}
PassRefPtr<PseudoElement> StyleResolver::createPseudoElementIfNeeded(Element& parent, PseudoId pseudoId)
......@@ -1100,7 +1099,7 @@ void StyleResolver::applyAnimatedProperties(StyleResolverState& state, const Wil
CSSPropertyID property = iter->key;
if (!isPropertyForPass<pass>(property))
continue;
const StyleInterpolation *interpolation = toStyleInterpolation(iter->value.get());
const StyleInterpolation* interpolation = toStyleInterpolation(iter->value.get());
interpolation->apply(state);
}
}
......
......@@ -122,7 +122,7 @@ public:
RuleMatchingBehavior = MatchAllRules);
PassRefPtr<RenderStyle> styleForKeyframe(Element*, const RenderStyle&, RenderStyle* parentStyle, const StyleKeyframe*, const AtomicString& animationName);
static PassRefPtrWillBeRawPtr<KeyframeEffectModel> createKeyframeEffectModel(Element&, const WillBeHeapVector<RefPtrWillBeMember<MutableStylePropertySet> >&, KeyframeEffectModel::KeyframeVector&);
static PassRefPtrWillBeRawPtr<AnimatableValueKeyframeEffectModel> createKeyframeEffectModel(Element&, const WillBeHeapVector<RefPtrWillBeMember<MutableStylePropertySet> >&, AnimatableValueKeyframeVector&);
PassRefPtr<RenderStyle> pseudoStyleForElement(Element*, const PseudoStyleRequest&, RenderStyle* parentStyle);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment