1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "config.h"
6#include "core/animation/StringKeyframe.h"
7
8#include "core/animation/DefaultStyleInterpolation.h"
9#include "core/animation/DeferredLegacyStyleInterpolation.h"
10#include "core/animation/LegacyStyleInterpolation.h"
11#include "core/animation/LengthStyleInterpolation.h"
12#include "core/animation/css/CSSAnimations.h"
13#include "core/css/CSSPropertyMetadata.h"
14#include "core/css/resolver/StyleResolver.h"
15#include "core/rendering/style/RenderStyle.h"
16
17namespace blink {
18
19StringKeyframe::StringKeyframe(const StringKeyframe& copyFrom)
20    : Keyframe(copyFrom.m_offset, copyFrom.m_composite, copyFrom.m_easing)
21    , m_propertySet(copyFrom.m_propertySet->mutableCopy())
22{
23}
24
25void StringKeyframe::setPropertyValue(CSSPropertyID property, const String& value, StyleSheetContents* styleSheetContents)
26{
27    ASSERT(property != CSSPropertyInvalid);
28    if (CSSAnimations::isAllowedAnimation(property))
29        m_propertySet->setProperty(property, value, false, styleSheetContents);
30}
31
32PropertySet StringKeyframe::properties() const
33{
34    // This is not used in time-critical code, so we probably don't need to
35    // worry about caching this result.
36    PropertySet properties;
37    for (unsigned i = 0; i < m_propertySet->propertyCount(); ++i)
38        properties.add(m_propertySet->propertyAt(i).id());
39    return properties;
40}
41
42PassRefPtrWillBeRawPtr<Keyframe> StringKeyframe::clone() const
43{
44    return adoptRefWillBeNoop(new StringKeyframe(*this));
45}
46PassOwnPtrWillBeRawPtr<Keyframe::PropertySpecificKeyframe> StringKeyframe::createPropertySpecificKeyframe(CSSPropertyID property) const
47{
48    return adoptPtrWillBeNoop(new PropertySpecificKeyframe(offset(), &easing(), propertyValue(property), composite()));
49}
50
51void StringKeyframe::trace(Visitor* visitor)
52{
53    visitor->trace(m_propertySet);
54    Keyframe::trace(visitor);
55}
56
57StringKeyframe::PropertySpecificKeyframe::PropertySpecificKeyframe(double offset, PassRefPtr<TimingFunction> easing, CSSValue* value, AnimationEffect::CompositeOperation op)
58    : Keyframe::PropertySpecificKeyframe(offset, easing, op)
59    , m_value(value)
60{ }
61
62StringKeyframe::PropertySpecificKeyframe::PropertySpecificKeyframe(double offset, PassRefPtr<TimingFunction> easing, CSSValue* value)
63    : Keyframe::PropertySpecificKeyframe(offset, easing, AnimationEffect::CompositeReplace)
64    , m_value(value)
65{
66    ASSERT(!isNull(m_offset));
67}
68
69PassRefPtrWillBeRawPtr<Interpolation> StringKeyframe::PropertySpecificKeyframe::createInterpolation(CSSPropertyID property, Keyframe::PropertySpecificKeyframe* end, Element* element) const
70{
71    CSSValue* fromCSSValue = m_value.get();
72    CSSValue* toCSSValue = toStringPropertySpecificKeyframe(end)->value();
73    ValueRange range = ValueRangeAll;
74
75    if (!CSSPropertyMetadata::isAnimatableProperty(property))
76        return DefaultStyleInterpolation::create(fromCSSValue, toCSSValue, property);
77
78    switch (property) {
79    case CSSPropertyBorderBottomWidth:
80    case CSSPropertyBorderLeftWidth:
81    case CSSPropertyBorderRightWidth:
82    case CSSPropertyBorderTopWidth:
83    case CSSPropertyFontSize:
84    case CSSPropertyHeight:
85    case CSSPropertyLineHeight:
86    case CSSPropertyMaxHeight:
87    case CSSPropertyMaxWidth:
88    case CSSPropertyMinHeight:
89    case CSSPropertyMinWidth:
90    case CSSPropertyOutlineWidth:
91    case CSSPropertyPaddingBottom:
92    case CSSPropertyPaddingLeft:
93    case CSSPropertyPaddingRight:
94    case CSSPropertyPaddingTop:
95    case CSSPropertyPerspective:
96    case CSSPropertyShapeMargin:
97    case CSSPropertyWidth:
98        range = ValueRangeNonNegative;
99        // Fall through
100    case CSSPropertyBottom:
101    case CSSPropertyLeft:
102    case CSSPropertyLetterSpacing:
103    case CSSPropertyMarginBottom:
104    case CSSPropertyMarginLeft:
105    case CSSPropertyMarginRight:
106    case CSSPropertyMarginTop:
107    case CSSPropertyOutlineOffset:
108    case CSSPropertyRight:
109    case CSSPropertyTop:
110    case CSSPropertyVerticalAlign:
111    case CSSPropertyWordSpacing:
112        if (LengthStyleInterpolation::canCreateFrom(*fromCSSValue) && LengthStyleInterpolation::canCreateFrom(*toCSSValue))
113            return LengthStyleInterpolation::create(fromCSSValue, toCSSValue, property, range);
114        break;
115    default:
116        break;
117    }
118
119    if (DeferredLegacyStyleInterpolation::interpolationRequiresStyleResolve(*fromCSSValue) || DeferredLegacyStyleInterpolation::interpolationRequiresStyleResolve(*toCSSValue))
120        return DeferredLegacyStyleInterpolation::create(fromCSSValue, toCSSValue, property);
121
122    // FIXME: Remove the use of AnimatableValues, RenderStyles and Elements here.
123    // FIXME: Remove this cache
124    ASSERT(element);
125    if (!m_animatableValueCache)
126        m_animatableValueCache = StyleResolver::createAnimatableValueSnapshot(*element, property, *fromCSSValue);
127
128    RefPtrWillBeRawPtr<AnimatableValue> to = StyleResolver::createAnimatableValueSnapshot(*element, property, *toCSSValue);
129    toStringPropertySpecificKeyframe(end)->m_animatableValueCache = to;
130
131    return LegacyStyleInterpolation::create(m_animatableValueCache.get(), to.release(), property);
132}
133
134PassOwnPtrWillBeRawPtr<Keyframe::PropertySpecificKeyframe> StringKeyframe::PropertySpecificKeyframe::neutralKeyframe(double offset, PassRefPtr<TimingFunction> easing) const
135{
136    return adoptPtrWillBeNoop(new PropertySpecificKeyframe(offset, easing, 0, AnimationEffect::CompositeAdd));
137}
138
139PassOwnPtrWillBeRawPtr<Keyframe::PropertySpecificKeyframe> StringKeyframe::PropertySpecificKeyframe::cloneWithOffset(double offset) const
140{
141    Keyframe::PropertySpecificKeyframe* theClone = new PropertySpecificKeyframe(offset, m_easing, m_value.get());
142    toStringPropertySpecificKeyframe(theClone)->m_animatableValueCache = m_animatableValueCache;
143    return adoptPtrWillBeNoop(theClone);
144}
145
146void StringKeyframe::PropertySpecificKeyframe::trace(Visitor* visitor)
147{
148    visitor->trace(m_value);
149    visitor->trace(m_animatableValueCache);
150    Keyframe::PropertySpecificKeyframe::trace(visitor);
151}
152
153}
154