OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2013 Google Inc. All rights reserved. | 2 * Copyright (C) 2013 Google Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
6 * met: | 6 * met: |
7 * | 7 * |
8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
(...skipping 18 matching lines...) Expand all Loading... |
29 */ | 29 */ |
30 | 30 |
31 #include "config.h" | 31 #include "config.h" |
32 #include "core/animation/KeyframeEffectModel.h" | 32 #include "core/animation/KeyframeEffectModel.h" |
33 | 33 |
34 #include "core/animation/TimedItem.h" | 34 #include "core/animation/TimedItem.h" |
35 #include "wtf/text/StringHash.h" | 35 #include "wtf/text/StringHash.h" |
36 | 36 |
37 namespace WebCore { | 37 namespace WebCore { |
38 | 38 |
39 Keyframe::Keyframe() | 39 bool Keyframe::compareOffsets(const RefPtrWillBeRawPtr<Keyframe>& a, const RefPt
rWillBeRawPtr<Keyframe>& b) |
40 : m_offset(nullValue()) | |
41 , m_composite(AnimationEffect::CompositeReplace) | |
42 , m_easing(LinearTimingFunction::preset()) | |
43 { } | |
44 | |
45 Keyframe::Keyframe(const Keyframe& copyFrom) | |
46 : m_offset(copyFrom.m_offset) | |
47 , m_composite(copyFrom.m_composite) | |
48 , m_easing(copyFrom.m_easing) | |
49 { | 40 { |
50 ASSERT(m_easing); | 41 return a->offset() < b->offset(); |
51 for (PropertyValueMap::const_iterator iter = copyFrom.m_propertyValues.begin
(); iter != copyFrom.m_propertyValues.end(); ++iter) | |
52 setPropertyValue(iter->key, iter->value.get()); | |
53 } | 42 } |
54 | 43 |
55 void Keyframe::setEasing(PassRefPtr<TimingFunction> easing) | 44 PropertySet KeyframeEffectModelBase::properties() const |
56 { | |
57 ASSERT(easing); | |
58 m_easing = easing; | |
59 } | |
60 | |
61 void Keyframe::setPropertyValue(CSSPropertyID property, const AnimatableValue* v
alue) | |
62 { | |
63 m_propertyValues.add(property, const_cast<AnimatableValue*>(value)); | |
64 } | |
65 | |
66 void Keyframe::clearPropertyValue(CSSPropertyID property) | |
67 { | |
68 m_propertyValues.remove(property); | |
69 } | |
70 | |
71 const AnimatableValue* Keyframe::propertyValue(CSSPropertyID property) const | |
72 { | |
73 ASSERT(m_propertyValues.contains(property)); | |
74 return m_propertyValues.get(property); | |
75 } | |
76 | |
77 PropertySet Keyframe::properties() const | |
78 { | |
79 // This is not used in time-critical code, so we probably don't need to | |
80 // worry about caching this result. | |
81 PropertySet properties; | |
82 for (PropertyValueMap::const_iterator iter = m_propertyValues.begin(); iter
!= m_propertyValues.end(); ++iter) | |
83 properties.add(*iter.keys()); | |
84 return properties; | |
85 } | |
86 | |
87 PassRefPtrWillBeRawPtr<Keyframe> Keyframe::cloneWithOffset(double offset) const | |
88 { | |
89 RefPtrWillBeRawPtr<Keyframe> theClone = clone(); | |
90 theClone->setOffset(offset); | |
91 return theClone.release(); | |
92 } | |
93 | |
94 void Keyframe::trace(Visitor* visitor) | |
95 { | |
96 visitor->trace(m_propertyValues); | |
97 } | |
98 | |
99 KeyframeEffectModel::KeyframeEffectModel(const KeyframeVector& keyframes) | |
100 : m_keyframes(keyframes) | |
101 { | |
102 } | |
103 | |
104 PropertySet KeyframeEffectModel::properties() const | |
105 { | 45 { |
106 PropertySet result; | 46 PropertySet result; |
107 if (!m_keyframes.size()) { | 47 if (!m_keyframes.size()) { |
108 return result; | 48 return result; |
109 } | 49 } |
110 result = m_keyframes[0]->properties(); | 50 result = m_keyframes[0]->properties(); |
111 for (size_t i = 1; i < m_keyframes.size(); i++) { | 51 for (size_t i = 1; i < m_keyframes.size(); i++) { |
112 PropertySet extras = m_keyframes[i]->properties(); | 52 PropertySet extras = m_keyframes[i]->properties(); |
113 for (PropertySet::const_iterator it = extras.begin(); it != extras.end()
; ++it) { | 53 for (PropertySet::const_iterator it = extras.begin(); it != extras.end()
; ++it) { |
114 result.add(*it); | 54 result.add(*it); |
115 } | 55 } |
116 } | 56 } |
117 return result; | 57 return result; |
118 } | 58 } |
119 | 59 |
120 PassOwnPtrWillBeRawPtr<WillBeHeapVector<RefPtrWillBeMember<Interpolation> > > Ke
yframeEffectModel::sample(int iteration, double fraction, double iterationDurati
on) const | 60 PassOwnPtrWillBeRawPtr<WillBeHeapVector<RefPtrWillBeMember<Interpolation> > > Ke
yframeEffectModelBase::sample(int iteration, double fraction, double iterationDu
ration) const |
121 { | 61 { |
122 ASSERT(iteration >= 0); | 62 ASSERT(iteration >= 0); |
123 ASSERT(!isNull(fraction)); | 63 ASSERT(!isNull(fraction)); |
124 ensureKeyframeGroups(); | 64 ensureKeyframeGroups(); |
125 ensureInterpolationEffect(); | 65 ensureInterpolationEffect(); |
126 | 66 |
127 return m_interpolationEffect->getActiveInterpolations(fraction, iterationDur
ation); | 67 return m_interpolationEffect->getActiveInterpolations(fraction, iterationDur
ation); |
128 } | 68 } |
129 | 69 |
130 KeyframeEffectModel::KeyframeVector KeyframeEffectModel::normalizedKeyframes(con
st KeyframeVector& keyframes) | 70 KeyframeEffectModelBase::KeyframeVector KeyframeEffectModelBase::normalizedKeyfr
ames(const KeyframeVector& keyframes) |
131 { | 71 { |
132 // keyframes [beginIndex, endIndex) will remain after removing all keyframes
if they are not | 72 // keyframes [beginIndex, endIndex) will remain after removing all keyframes
if they are not |
133 // loosely sorted by offset, and after removing keyframes with positional of
fset outide [0, 1]. | 73 // loosely sorted by offset, and after removing keyframes with positional of
fset outide [0, 1]. |
134 size_t beginIndex = 0; | 74 size_t beginIndex = 0; |
135 size_t endIndex = keyframes.size(); | 75 size_t endIndex = keyframes.size(); |
136 | 76 |
137 // Becomes the most recent keyframe with an explicit offset. | 77 // Becomes the most recent keyframe with an explicit offset. |
138 size_t lastIndex = endIndex; | 78 size_t lastIndex = endIndex; |
139 double lastOffset = std::numeric_limits<double>::quiet_NaN(); | 79 double lastOffset = std::numeric_limits<double>::quiet_NaN(); |
140 | 80 |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
184 result[lastIndex + j]->setOffset(lastOffset + (offset -
lastOffset) * j / (i - lastIndex)); | 124 result[lastIndex + j]->setOffset(lastOffset + (offset -
lastOffset) * j / (i - lastIndex)); |
185 } | 125 } |
186 lastIndex = i; | 126 lastIndex = i; |
187 lastOffset = offset; | 127 lastOffset = offset; |
188 } | 128 } |
189 } | 129 } |
190 } | 130 } |
191 return result; | 131 return result; |
192 } | 132 } |
193 | 133 |
194 void KeyframeEffectModel::ensureKeyframeGroups() const | 134 |
| 135 void KeyframeEffectModelBase::ensureKeyframeGroups() const |
195 { | 136 { |
196 if (m_keyframeGroups) | 137 if (m_keyframeGroups) |
197 return; | 138 return; |
198 | 139 |
199 m_keyframeGroups = adoptPtrWillBeNoop(new KeyframeGroupMap); | 140 m_keyframeGroups = adoptPtrWillBeNoop(new KeyframeGroupMap); |
200 const KeyframeVector keyframes = normalizedKeyframes(getFrames()); | 141 const KeyframeVector keyframes = normalizedKeyframes(getFrames()); |
201 for (KeyframeVector::const_iterator keyframeIter = keyframes.begin(); keyfra
meIter != keyframes.end(); ++keyframeIter) { | 142 for (KeyframeVector::const_iterator keyframeIter = keyframes.begin(); keyfra
meIter != keyframes.end(); ++keyframeIter) { |
202 const Keyframe* keyframe = keyframeIter->get(); | 143 const Keyframe* keyframe = keyframeIter->get(); |
203 PropertySet keyframeProperties = keyframe->properties(); | 144 PropertySet keyframeProperties = keyframe->properties(); |
204 for (PropertySet::const_iterator propertyIter = keyframeProperties.begin
(); propertyIter != keyframeProperties.end(); ++propertyIter) { | 145 for (PropertySet::const_iterator propertyIter = keyframeProperties.begin
(); propertyIter != keyframeProperties.end(); ++propertyIter) { |
205 CSSPropertyID property = *propertyIter; | 146 CSSPropertyID property = *propertyIter; |
206 KeyframeGroupMap::iterator groupIter = m_keyframeGroups->find(proper
ty); | 147 KeyframeGroupMap::iterator groupIter = m_keyframeGroups->find(proper
ty); |
207 PropertySpecificKeyframeGroup* group; | 148 PropertySpecificKeyframeGroup* group; |
208 if (groupIter == m_keyframeGroups->end()) | 149 if (groupIter == m_keyframeGroups->end()) |
209 group = m_keyframeGroups->add(property, adoptPtrWillBeNoop(new P
ropertySpecificKeyframeGroup)).storedValue->value.get(); | 150 group = m_keyframeGroups->add(property, adoptPtrWillBeNoop(new P
ropertySpecificKeyframeGroup)).storedValue->value.get(); |
210 else | 151 else |
211 group = groupIter->value.get(); | 152 group = groupIter->value.get(); |
212 | 153 |
213 ASSERT(keyframe->composite() == AnimationEffect::CompositeReplace); | 154 ASSERT(keyframe->composite() == AnimationEffect::CompositeReplace); |
214 group->appendKeyframe(adoptPtrWillBeNoop( | 155 group->appendKeyframe(keyframe->createPropertySpecificKeyframe(prope
rty)); |
215 new PropertySpecificKeyframe(keyframe->offset(), keyframe->easin
g(), keyframe->propertyValue(property), keyframe->composite()))); | |
216 } | 156 } |
217 } | 157 } |
218 | 158 |
219 // Add synthetic keyframes. | 159 // Add synthetic keyframes. |
220 for (KeyframeGroupMap::iterator iter = m_keyframeGroups->begin(); iter != m_
keyframeGroups->end(); ++iter) { | 160 for (KeyframeGroupMap::iterator iter = m_keyframeGroups->begin(); iter != m_
keyframeGroups->end(); ++iter) { |
221 iter->value->addSyntheticKeyframeIfRequired(); | 161 iter->value->addSyntheticKeyframeIfRequired(this); |
222 iter->value->removeRedundantKeyframes(); | 162 iter->value->removeRedundantKeyframes(); |
223 } | 163 } |
224 } | 164 } |
225 | 165 |
226 void KeyframeEffectModel::ensureInterpolationEffect() const | 166 void KeyframeEffectModelBase::ensureInterpolationEffect() const |
227 { | 167 { |
228 if (m_interpolationEffect) | 168 if (m_interpolationEffect) |
229 return; | 169 return; |
230 m_interpolationEffect = InterpolationEffect::create(); | 170 m_interpolationEffect = InterpolationEffect::create(); |
231 | 171 |
232 for (KeyframeGroupMap::const_iterator iter = m_keyframeGroups->begin(); iter
!= m_keyframeGroups->end(); ++iter) { | 172 for (KeyframeGroupMap::const_iterator iter = m_keyframeGroups->begin(); iter
!= m_keyframeGroups->end(); ++iter) { |
233 const PropertySpecificKeyframeVector& keyframes = iter->value->keyframes
(); | 173 const PropertySpecificKeyframeVector& keyframes = iter->value->keyframes
(); |
234 ASSERT(keyframes[0]->composite() == AnimationEffect::CompositeReplace); | 174 ASSERT(keyframes[0]->composite() == AnimationEffect::CompositeReplace); |
235 const AnimatableValue* start; | |
236 const AnimatableValue* end = keyframes[0]->value(); | |
237 for (size_t i = 0; i < keyframes.size() - 1; i++) { | 175 for (size_t i = 0; i < keyframes.size() - 1; i++) { |
238 ASSERT(keyframes[i + 1]->composite() == AnimationEffect::CompositeRe
place); | 176 ASSERT(keyframes[i + 1]->composite() == AnimationEffect::CompositeRe
place); |
239 start = end; | |
240 end = keyframes[i + 1]->value(); | |
241 double applyFrom = i ? keyframes[i]->offset() : (-std::numeric_limit
s<double>::infinity()); | 177 double applyFrom = i ? keyframes[i]->offset() : (-std::numeric_limit
s<double>::infinity()); |
242 double applyTo = i == keyframes.size() - 2 ? std::numeric_limits<dou
ble>::infinity() : keyframes[i + 1]->offset(); | 178 double applyTo = i == keyframes.size() - 2 ? std::numeric_limits<dou
ble>::infinity() : keyframes[i + 1]->offset(); |
243 if (applyTo == 1) | 179 if (applyTo == 1) |
244 applyTo = std::numeric_limits<double>::infinity(); | 180 applyTo = std::numeric_limits<double>::infinity(); |
245 m_interpolationEffect->addInterpolation( | 181 |
246 LegacyStyleInterpolation::create( | 182 m_interpolationEffect->addInterpolation(keyframes[i]->createInterpol
ation(iter->key, keyframes[i + 1].get()), |
247 AnimatableValue::takeConstRef(start), | |
248 AnimatableValue::takeConstRef(end), iter->key), | |
249 keyframes[i]->easing(), keyframes[i]->offset(), keyframes[i + 1]
->offset(), applyFrom, applyTo); | 183 keyframes[i]->easing(), keyframes[i]->offset(), keyframes[i + 1]
->offset(), applyFrom, applyTo); |
250 } | 184 } |
251 } | 185 } |
252 } | 186 } |
253 | 187 |
254 bool KeyframeEffectModel::isReplaceOnly() | 188 bool KeyframeEffectModelBase::isReplaceOnly() |
255 { | 189 { |
256 ensureKeyframeGroups(); | 190 ensureKeyframeGroups(); |
257 for (KeyframeGroupMap::iterator iter = m_keyframeGroups->begin(); iter != m_
keyframeGroups->end(); ++iter) { | 191 for (KeyframeGroupMap::iterator iter = m_keyframeGroups->begin(); iter != m_
keyframeGroups->end(); ++iter) { |
258 const PropertySpecificKeyframeVector& keyframeVector = iter->value->keyf
rames(); | 192 const PropertySpecificKeyframeVector& keyframeVector = iter->value->keyf
rames(); |
259 for (size_t i = 0; i < keyframeVector.size(); ++i) { | 193 for (size_t i = 0; i < keyframeVector.size(); ++i) { |
260 if (keyframeVector[i]->composite() != AnimationEffect::CompositeRepl
ace) | 194 if (keyframeVector[i]->composite() != AnimationEffect::CompositeRepl
ace) |
261 return false; | 195 return false; |
262 } | 196 } |
263 } | 197 } |
264 return true; | 198 return true; |
265 } | 199 } |
266 | 200 |
267 void KeyframeEffectModel::trace(Visitor* visitor) | 201 void KeyframeEffectModelBase::trace(Visitor* visitor) |
268 { | 202 { |
269 visitor->trace(m_keyframes); | 203 visitor->trace(m_keyframes); |
270 visitor->trace(m_interpolationEffect); | 204 visitor->trace(m_interpolationEffect); |
271 #if ENABLE_OILPAN | 205 #if ENABLE_OILPAN |
272 visitor->trace(m_keyframeGroups); | 206 visitor->trace(m_keyframeGroups); |
273 #endif | 207 #endif |
274 } | 208 } |
275 | 209 |
276 KeyframeEffectModel::PropertySpecificKeyframe::PropertySpecificKeyframe(double o
ffset, PassRefPtr<TimingFunction> easing, const AnimatableValue* value, Composit
eOperation composite) | 210 Keyframe::PropertySpecificKeyframe::PropertySpecificKeyframe(double offset, Pass
RefPtr<TimingFunction> easing, AnimationEffect::CompositeOperation composite) |
277 : m_offset(offset) | 211 : m_offset(offset) |
278 , m_easing(easing) | 212 , m_easing(easing) |
279 , m_composite(composite) | 213 , m_composite(composite) |
280 { | 214 { |
281 m_value = AnimatableValue::takeConstRef(value); | |
282 } | 215 } |
283 | 216 |
284 KeyframeEffectModel::PropertySpecificKeyframe::PropertySpecificKeyframe(double o
ffset, PassRefPtr<TimingFunction> easing, PassRefPtrWillBeRawPtr<AnimatableValue
> value, CompositeOperation composite) | 217 void KeyframeEffectModelBase::PropertySpecificKeyframeGroup::appendKeyframe(Pass
OwnPtr<PropertySpecificKeyframe> keyframe) |
285 : m_offset(offset) | |
286 , m_easing(easing) | |
287 , m_value(value) | |
288 , m_composite(composite) | |
289 { | |
290 ASSERT(!isNull(m_offset)); | |
291 } | |
292 | |
293 PassOwnPtrWillBeRawPtr<KeyframeEffectModel::PropertySpecificKeyframe> KeyframeEf
fectModel::PropertySpecificKeyframe::cloneWithOffset(double offset) const | |
294 { | |
295 return adoptPtrWillBeNoop(new PropertySpecificKeyframe(offset, m_easing, m_v
alue.get(), m_composite)); | |
296 } | |
297 | |
298 void KeyframeEffectModel::PropertySpecificKeyframe::trace(Visitor* visitor) | |
299 { | |
300 visitor->trace(m_value); | |
301 } | |
302 | |
303 void KeyframeEffectModel::PropertySpecificKeyframeGroup::appendKeyframe(PassOwnP
trWillBeRawPtr<PropertySpecificKeyframe> keyframe) | |
304 { | 218 { |
305 ASSERT(m_keyframes.isEmpty() || m_keyframes.last()->offset() <= keyframe->of
fset()); | 219 ASSERT(m_keyframes.isEmpty() || m_keyframes.last()->offset() <= keyframe->of
fset()); |
306 m_keyframes.append(keyframe); | 220 m_keyframes.append(keyframe); |
307 } | 221 } |
308 | 222 |
309 void KeyframeEffectModel::PropertySpecificKeyframeGroup::removeRedundantKeyframe
s() | 223 void KeyframeEffectModelBase::PropertySpecificKeyframeGroup::removeRedundantKeyf
rames() |
310 { | 224 { |
311 // As an optimization, removes keyframes in the following categories, as | 225 // As an optimization, removes keyframes in the following categories, as |
312 // they will never be used by sample(). | 226 // they will never be used by sample(). |
313 // - End keyframes with the same offset as their neighbor | 227 // - End keyframes with the same offset as their neighbor |
314 // - Interior keyframes with the same offset as both their neighbors | 228 // - Interior keyframes with the same offset as both their neighbors |
315 // Note that synthetic keyframes must be added before this method is | 229 // Note that synthetic keyframes must be added before this method is |
316 // called. | 230 // called. |
317 ASSERT(m_keyframes.size() >= 2); | 231 ASSERT(m_keyframes.size() >= 2); |
318 for (int i = m_keyframes.size() - 1; i >= 0; --i) { | 232 for (int i = m_keyframes.size() - 1; i >= 0; --i) { |
319 double offset = m_keyframes[i]->offset(); | 233 double offset = m_keyframes[i]->offset(); |
320 bool hasSameOffsetAsPreviousNeighbor = !i || m_keyframes[i - 1]->offset(
) == offset; | 234 bool hasSameOffsetAsPreviousNeighbor = !i || m_keyframes[i - 1]->offset(
) == offset; |
321 bool hasSameOffsetAsNextNeighbor = i == static_cast<int>(m_keyframes.siz
e() - 1) || m_keyframes[i + 1]->offset() == offset; | 235 bool hasSameOffsetAsNextNeighbor = i == static_cast<int>(m_keyframes.siz
e() - 1) || m_keyframes[i + 1]->offset() == offset; |
322 if (hasSameOffsetAsPreviousNeighbor && hasSameOffsetAsNextNeighbor) | 236 if (hasSameOffsetAsPreviousNeighbor && hasSameOffsetAsNextNeighbor) |
323 m_keyframes.remove(i); | 237 m_keyframes.remove(i); |
324 } | 238 } |
325 ASSERT(m_keyframes.size() >= 2); | 239 ASSERT(m_keyframes.size() >= 2); |
326 } | 240 } |
327 | 241 |
328 void KeyframeEffectModel::PropertySpecificKeyframeGroup::addSyntheticKeyframeIfR
equired() | 242 void KeyframeEffectModelBase::PropertySpecificKeyframeGroup::addSyntheticKeyfram
eIfRequired(const KeyframeEffectModelBase* context) |
329 { | 243 { |
330 ASSERT(!m_keyframes.isEmpty()); | 244 ASSERT(!m_keyframes.isEmpty()); |
331 if (m_keyframes.first()->offset() != 0.0) | 245 if (m_keyframes.first()->offset() != 0.0) |
332 m_keyframes.insert(0, adoptPtrWillBeNoop(new PropertySpecificKeyframe(0,
nullptr, AnimatableValue::neutralValue(), CompositeAdd))); | 246 m_keyframes.insert(0, m_keyframes.first()->neutralKeyframe(0, nullptr)); |
333 if (m_keyframes.last()->offset() != 1.0) | 247 if (m_keyframes.last()->offset() != 1.0) |
334 appendKeyframe(adoptPtrWillBeNoop(new PropertySpecificKeyframe(1, nullpt
r, AnimatableValue::neutralValue(), CompositeAdd))); | 248 appendKeyframe(m_keyframes.last()->neutralKeyframe(1, nullptr)); |
335 } | 249 } |
336 | 250 |
337 void KeyframeEffectModel::PropertySpecificKeyframeGroup::trace(Visitor* visitor) | 251 void KeyframeEffectModelBase::PropertySpecificKeyframeGroup::trace(Visitor* visi
tor) |
338 { | 252 { |
339 #if ENABLE_OILPAN | 253 #if ENABLE(OILPAN) |
340 visitor->trace(m_keyframes); | 254 visitor->trace(m_keyframes); |
341 #endif | 255 #endif |
342 } | 256 } |
343 | 257 |
| 258 template <> |
| 259 bool KeyframeEffectModel<AnimatableValueKeyframe>::isAnimatableValueKeyframeEffe
ctModel() const { return true; } |
| 260 |
| 261 template <> |
| 262 bool KeyframeEffectModel<StringKeyframe>::isStringKeyframeEffectModel() const {
return true; } |
| 263 |
344 } // namespace | 264 } // namespace |
OLD | NEW |