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

Side by Side Diff: Source/core/animation/KeyframeEffectModel.cpp

Issue 194673002: Web Animations: Refactor KeyframeEffectModel to work via an InterpolationEffect. (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@interpolationWrap
Patch Set: Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 16 matching lines...) Expand all
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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 {
38
39 using namespace WebCore;
40
41 class AddCompositableValue FINAL : public AnimationEffect::CompositableValue {
42 public:
43 static PassRefPtr<AddCompositableValue> create(const AnimatableValue* value)
44 {
45 return adoptRef(new AddCompositableValue(value));
46 }
47 virtual bool dependsOnUnderlyingValue() const OVERRIDE
48 {
49 return true;
50 }
51 virtual PassRefPtr<AnimatableValue> compositeOnto(const AnimatableValue* und erlyingValue) const OVERRIDE
52 {
53 return AnimatableValue::add(underlyingValue, m_value.get());
54 }
55 private:
56 AddCompositableValue(const AnimatableValue* value)
57 : m_value(const_cast<AnimatableValue*>(value))
58 {
59 }
60 RefPtr<AnimatableValue> m_value;
61 };
62
63 class BlendedCompositableValue FINAL : public AnimationEffect::CompositableValue {
64 public:
65 static PassRefPtr<BlendedCompositableValue> create(const AnimationEffect::Co mpositableValue* before, const AnimationEffect::CompositableValue* after, double fraction)
66 {
67 return adoptRef(new BlendedCompositableValue(before, after, fraction));
68 }
69 virtual bool dependsOnUnderlyingValue() const OVERRIDE
70 {
71 return m_dependsOnUnderlyingValue;
72 }
73 virtual PassRefPtr<AnimatableValue> compositeOnto(const AnimatableValue* und erlyingValue) const OVERRIDE
74 {
75 return AnimatableValue::interpolate(m_before->compositeOnto(underlyingVa lue).get(), m_after->compositeOnto(underlyingValue).get(), m_fraction);
76 }
77 private:
78 BlendedCompositableValue(const AnimationEffect::CompositableValue* before, c onst AnimationEffect::CompositableValue* after, double fraction)
79 : m_before(const_cast<AnimationEffect::CompositableValue*>(before))
80 , m_after(const_cast<AnimationEffect::CompositableValue*>(after))
81 , m_fraction(fraction)
82 , m_dependsOnUnderlyingValue(before->dependsOnUnderlyingValue() || after ->dependsOnUnderlyingValue())
83 { }
84 RefPtr<AnimationEffect::CompositableValue> m_before;
85 RefPtr<AnimationEffect::CompositableValue> m_after;
86 double m_fraction;
87 bool m_dependsOnUnderlyingValue;
88 };
89
90 const double accuracyForKeyframeEasing = 0.0000001;
91
92 } // namespace
93
94
95 namespace WebCore { 37 namespace WebCore {
96 38
97 Keyframe::Keyframe() 39 Keyframe::Keyframe()
98 : m_offset(nullValue()) 40 : m_offset(nullValue())
99 , m_composite(AnimationEffect::CompositeReplace) 41 , m_composite(AnimationEffect::CompositeReplace)
100 , m_easing(LinearTimingFunction::preset()) 42 , m_easing(LinearTimingFunction::preset())
101 { } 43 { }
102 44
103 Keyframe::Keyframe(const Keyframe& copyFrom) 45 Keyframe::Keyframe(const Keyframe& copyFrom)
104 : m_offset(copyFrom.m_offset) 46 : m_offset(copyFrom.m_offset)
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
163 result = m_keyframes[0]->properties(); 105 result = m_keyframes[0]->properties();
164 for (size_t i = 1; i < m_keyframes.size(); i++) { 106 for (size_t i = 1; i < m_keyframes.size(); i++) {
165 PropertySet extras = m_keyframes[i]->properties(); 107 PropertySet extras = m_keyframes[i]->properties();
166 for (PropertySet::const_iterator it = extras.begin(); it != extras.end() ; ++it) { 108 for (PropertySet::const_iterator it = extras.begin(); it != extras.end() ; ++it) {
167 result.add(*it); 109 result.add(*it);
168 } 110 }
169 } 111 }
170 return result; 112 return result;
171 } 113 }
172 114
173 PassOwnPtr<AnimationEffect::CompositableValueList> KeyframeEffectModel::sample(i nt iteration, double fraction) const 115 PassOwnPtr<Vector<RefPtr<Interpolation> > > KeyframeEffectModel::sample(int iter ation, double fraction) const
174 { 116 {
175 ASSERT(iteration >= 0); 117 ASSERT(iteration >= 0);
176 ASSERT(!isNull(fraction)); 118 ASSERT(!isNull(fraction));
177 const_cast<KeyframeEffectModel*>(this)->ensureKeyframeGroups(); 119 ensureKeyframeGroups();
178 OwnPtr<CompositableValueList> map = adoptPtr(new CompositableValueList()); 120 ensureInterpolationEffect();
179 for (KeyframeGroupMap::const_iterator iter = m_keyframeGroups->begin(); iter != m_keyframeGroups->end(); ++iter) 121
180 map->append(std::make_pair(iter->key, iter->value->sample(iteration, fra ction))); 122 return m_interpolationEffect->getActiveInterpolations(fraction);
181 return map.release();
182 } 123 }
183 124
184 KeyframeEffectModel::KeyframeVector KeyframeEffectModel::normalizedKeyframes(con st KeyframeVector& keyframes) 125 KeyframeEffectModel::KeyframeVector KeyframeEffectModel::normalizedKeyframes(con st KeyframeVector& keyframes)
185 { 126 {
186 // keyframes [beginIndex, endIndex) will remain after removing all keyframes if they are not 127 // keyframes [beginIndex, endIndex) will remain after removing all keyframes if they are not
187 // loosely sorted by offset, and after removing keyframes with positional of fset outide [0, 1]. 128 // loosely sorted by offset, and after removing keyframes with positional of fset outide [0, 1].
188 size_t beginIndex = 0; 129 size_t beginIndex = 0;
189 size_t endIndex = keyframes.size(); 130 size_t endIndex = keyframes.size();
190 131
191 // Becomes the most recent keyframe with an explicit offset. 132 // Becomes the most recent keyframe with an explicit offset.
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
269 } 210 }
270 } 211 }
271 212
272 // Add synthetic keyframes. 213 // Add synthetic keyframes.
273 for (KeyframeGroupMap::iterator iter = m_keyframeGroups->begin(); iter != m_ keyframeGroups->end(); ++iter) { 214 for (KeyframeGroupMap::iterator iter = m_keyframeGroups->begin(); iter != m_ keyframeGroups->end(); ++iter) {
274 iter->value->addSyntheticKeyframeIfRequired(); 215 iter->value->addSyntheticKeyframeIfRequired();
275 iter->value->removeRedundantKeyframes(); 216 iter->value->removeRedundantKeyframes();
276 } 217 }
277 } 218 }
278 219
220 void KeyframeEffectModel::ensureInterpolationEffect() const
221 {
222 if (m_interpolationEffect)
223 return;
224 m_interpolationEffect = InterpolationEffect::create();
225
226 for (KeyframeGroupMap::const_iterator iter = m_keyframeGroups->begin(); iter != m_keyframeGroups->end(); ++iter) {
227 const PropertySpecificKeyframeVector& keyframes = iter->value->keyframes ();
228 const AnimatableValue* start;
229 const AnimatableValue* end = keyframes[0]->value();
230 for (size_t i = 0; i < keyframes.size() - 1; i++) {
231 start = end;
232 end = keyframes[i+1]->value();
dstockwell 2014/03/17 02:05:57 spaces around +, and below
shans 2014/03/18 20:09:28 Done.
233 double applyFrom = i ? keyframes[i]->offset() : (-std::numeric_limit s<double>::infinity());
234 double applyTo = i == keyframes.size() - 2 ? std::numeric_limits<dou ble>::infinity() : keyframes[i+1]->offset();
235 if (applyTo == 1)
236 applyTo = std::numeric_limits<double>::infinity();
237 m_interpolationEffect->addInterpolation(
238 LegacyStyleInterpolation::create(
239 AnimatableValue::takeConstRef(start),
240 AnimatableValue::takeConstRef(end), iter->key),
241 keyframes[i]->easing(), keyframes[i]->offset(), keyframes[i+1]-> offset(), applyFrom, applyTo);
242 }
243 }
244 }
279 245
280 KeyframeEffectModel::PropertySpecificKeyframe::PropertySpecificKeyframe(double o ffset, PassRefPtr<TimingFunction> easing, const AnimatableValue* value, Composit eOperation composite) 246 KeyframeEffectModel::PropertySpecificKeyframe::PropertySpecificKeyframe(double o ffset, PassRefPtr<TimingFunction> easing, const AnimatableValue* value, Composit eOperation composite)
281 : m_offset(offset) 247 : m_offset(offset)
282 , m_easing(easing) 248 , m_easing(easing)
283 , m_value(composite == AnimationEffect::CompositeReplace ?
284 AnimatableValue::takeConstRef(value) :
285 static_cast<PassRefPtr<CompositableValue> >(AddCompositableValue::create (value)))
286 { 249 {
250 ASSERT(composite == AnimationEffect::CompositeReplace);
251 m_value = AnimatableValue::takeConstRef(value);
287 } 252 }
288 253
289 KeyframeEffectModel::PropertySpecificKeyframe::PropertySpecificKeyframe(double o ffset, PassRefPtr<TimingFunction> easing, PassRefPtr<CompositableValue> value) 254 KeyframeEffectModel::PropertySpecificKeyframe::PropertySpecificKeyframe(double o ffset, PassRefPtr<TimingFunction> easing, PassRefPtr<AnimatableValue> value)
290 : m_offset(offset) 255 : m_offset(offset)
291 , m_easing(easing) 256 , m_easing(easing)
292 , m_value(value) 257 , m_value(value)
293 { 258 {
294 ASSERT(!isNull(m_offset)); 259 ASSERT(!isNull(m_offset));
295 } 260 }
296 261
297 PassOwnPtr<KeyframeEffectModel::PropertySpecificKeyframe> KeyframeEffectModel::P ropertySpecificKeyframe::cloneWithOffset(double offset) const 262 PassOwnPtr<KeyframeEffectModel::PropertySpecificKeyframe> KeyframeEffectModel::P ropertySpecificKeyframe::cloneWithOffset(double offset) const
298 { 263 {
299 return adoptPtr(new PropertySpecificKeyframe(offset, m_easing, PassRefPtr<Co mpositableValue>(m_value))); 264 return adoptPtr(new PropertySpecificKeyframe(offset, m_easing, m_value));
300 } 265 }
301 266
302 267
303 void KeyframeEffectModel::PropertySpecificKeyframeGroup::appendKeyframe(PassOwnP tr<PropertySpecificKeyframe> keyframe) 268 void KeyframeEffectModel::PropertySpecificKeyframeGroup::appendKeyframe(PassOwnP tr<PropertySpecificKeyframe> keyframe)
304 { 269 {
305 ASSERT(m_keyframes.isEmpty() || m_keyframes.last()->offset() <= keyframe->of fset()); 270 ASSERT(m_keyframes.isEmpty() || m_keyframes.last()->offset() <= keyframe->of fset());
306 m_keyframes.append(keyframe); 271 m_keyframes.append(keyframe);
307 } 272 }
308 273
309 void KeyframeEffectModel::PropertySpecificKeyframeGroup::removeRedundantKeyframe s() 274 void KeyframeEffectModel::PropertySpecificKeyframeGroup::removeRedundantKeyframe s()
(...skipping 28 matching lines...) Expand all
338 } 303 }
339 if (!allOffsetsEqual) 304 if (!allOffsetsEqual)
340 return; 305 return;
341 306
342 if (!offset) 307 if (!offset)
343 appendKeyframe(m_keyframes.first()->cloneWithOffset(1.0)); 308 appendKeyframe(m_keyframes.first()->cloneWithOffset(1.0));
344 else 309 else
345 m_keyframes.insert(0, adoptPtr(new PropertySpecificKeyframe(0.0, nullptr , AnimatableValue::neutralValue(), CompositeAdd))); 310 m_keyframes.insert(0, adoptPtr(new PropertySpecificKeyframe(0.0, nullptr , AnimatableValue::neutralValue(), CompositeAdd)));
346 } 311 }
347 312
348 PassRefPtr<AnimationEffect::CompositableValue> KeyframeEffectModel::PropertySpec ificKeyframeGroup::sample(int iteration, double offset) const
349 {
350 // FIXME: Implement accumulation.
351 ASSERT_UNUSED(iteration, iteration >= 0);
352 ASSERT(!isNull(offset));
353
354 // Bail if offset is null, as this can lead to buffer overflow below.
355 if (isNull(offset))
356 return const_cast<CompositableValue*>(m_keyframes.first()->value());
357
358 double minimumOffset = m_keyframes.first()->offset();
359 double maximumOffset = m_keyframes.last()->offset();
360 ASSERT(minimumOffset != maximumOffset);
361
362 PropertySpecificKeyframeVector::const_iterator before;
363 PropertySpecificKeyframeVector::const_iterator after;
364
365 // Note that this algorithm is simpler than that in the spec because we
366 // have removed keyframes with equal offsets in
367 // removeRedundantKeyframes().
368 if (offset < minimumOffset) {
369 before = m_keyframes.begin();
370 after = before + 1;
371 ASSERT((*before)->offset() > offset);
372 ASSERT((*after)->offset() > offset);
373 } else if (offset >= maximumOffset) {
374 after = m_keyframes.end() - 1;
375 before = after - 1;
376 ASSERT((*before)->offset() < offset);
377 ASSERT((*after)->offset() <= offset);
378 } else {
379 // FIXME: This is inefficient for large numbers of keyframes. Consider
380 // using binary search.
381 after = m_keyframes.begin();
382 while ((*after)->offset() <= offset)
383 ++after;
384 before = after - 1;
385 ASSERT((*before)->offset() <= offset);
386 ASSERT((*after)->offset() > offset);
387 }
388
389 if ((*before)->offset() == offset)
390 return const_cast<CompositableValue*>((*before)->value());
391 if ((*after)->offset() == offset)
392 return const_cast<CompositableValue*>((*after)->value());
393
394 double fraction = (offset - (*before)->offset()) / ((*after)->offset() - (*b efore)->offset());
395 if (const TimingFunction* timingFunction = (*before)->easing())
396 fraction = timingFunction->evaluate(fraction, accuracyForKeyframeEasing) ;
397 return BlendedCompositableValue::create((*before)->value(), (*after)->value( ), fraction);
398 }
399
400 void KeyframeEffectModel::trace(Visitor* visitor) 313 void KeyframeEffectModel::trace(Visitor* visitor)
401 { 314 {
402 visitor->trace(m_keyframes); 315 visitor->trace(m_keyframes);
403 } 316 }
404 317
405 } // namespace 318 } // namespace
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698