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

Side by Side Diff: Source/core/animation/css/CSSAnimations.cpp

Issue 26382004: Web Animations CSS: Implement CSS Transitions backed on Web Animations model (Closed) Base URL: https://chromium.googlesource.com/chromium/blink@master
Patch Set: store animatablevalues explicitly Created 7 years, 2 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
« no previous file with comments | « Source/core/animation/css/CSSAnimations.h ('k') | Source/core/css/resolver/StyleAdjuster.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 13 matching lines...) Expand all
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
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/css/CSSAnimations.h" 32 #include "core/animation/css/CSSAnimations.h"
33 33
34 #include "StylePropertyShorthand.h"
34 #include "core/animation/ActiveAnimations.h" 35 #include "core/animation/ActiveAnimations.h"
35 #include "core/animation/DocumentTimeline.h" 36 #include "core/animation/DocumentTimeline.h"
36 #include "core/animation/KeyframeAnimationEffect.h" 37 #include "core/animation/KeyframeAnimationEffect.h"
38 #include "core/animation/css/CSSAnimatableValueFactory.h"
37 #include "core/css/CSSKeyframeRule.h" 39 #include "core/css/CSSKeyframeRule.h"
38 #include "core/css/resolver/StyleResolver.h" 40 #include "core/css/resolver/StyleResolver.h"
39 #include "core/dom/Element.h" 41 #include "core/dom/Element.h"
40 #include "core/events/ThreadLocalEventNames.h" 42 #include "core/events/ThreadLocalEventNames.h"
43 #include "core/events/TransitionEvent.h"
41 #include "core/events/WebKitAnimationEvent.h" 44 #include "core/events/WebKitAnimationEvent.h"
42 #include "core/platform/animation/CSSAnimationDataList.h" 45 #include "core/platform/animation/CSSAnimationDataList.h"
43 #include "core/platform/animation/TimingFunction.h" 46 #include "core/platform/animation/TimingFunction.h"
44 #include "wtf/HashSet.h" 47 #include "wtf/HashSet.h"
45 48
49 namespace WebCore {
50
46 namespace { 51 namespace {
47 52
48 using namespace WebCore;
49
50 bool isEarlierPhase(TimedItem::Phase target, TimedItem::Phase reference) 53 bool isEarlierPhase(TimedItem::Phase target, TimedItem::Phase reference)
51 { 54 {
52 ASSERT(target != TimedItem::PhaseNone); 55 ASSERT(target != TimedItem::PhaseNone);
53 ASSERT(reference != TimedItem::PhaseNone); 56 ASSERT(reference != TimedItem::PhaseNone);
54 return target < reference; 57 return target < reference;
55 } 58 }
56 59
57 bool isLaterPhase(TimedItem::Phase target, TimedItem::Phase reference) 60 bool isLaterPhase(TimedItem::Phase target, TimedItem::Phase reference)
58 { 61 {
59 ASSERT(target != TimedItem::PhaseNone); 62 ASSERT(target != TimedItem::PhaseNone);
60 ASSERT(reference != TimedItem::PhaseNone); 63 ASSERT(reference != TimedItem::PhaseNone);
61 return target > reference; 64 return target > reference;
62 } 65 }
63 66
64 } // namespace
65
66 namespace WebCore {
67
68 // Returns the default timing function. 67 // Returns the default timing function.
69 const PassRefPtr<TimingFunction> timingFromAnimationData(const CSSAnimationData* animationData, Timing& timing) 68 const PassRefPtr<TimingFunction> timingFromAnimationData(const CSSAnimationData* animationData, Timing& timing)
70 { 69 {
71 if (animationData->isDelaySet()) 70 if (animationData->isDelaySet())
72 timing.startDelay = animationData->delay(); 71 timing.startDelay = animationData->delay();
73 if (animationData->isDurationSet()) { 72 if (animationData->isDurationSet()) {
74 timing.iterationDuration = animationData->duration(); 73 timing.iterationDuration = animationData->duration();
75 timing.hasIterationDuration = true; 74 timing.hasIterationDuration = true;
76 } 75 }
77 if (animationData->isIterationCountSet()) { 76 if (animationData->isIterationCountSet()) {
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
112 case CSSAnimationData::AnimationDirectionAlternateReverse: 111 case CSSAnimationData::AnimationDirectionAlternateReverse:
113 timing.direction = Timing::PlaybackDirectionAlternateReverse; 112 timing.direction = Timing::PlaybackDirectionAlternateReverse;
114 break; 113 break;
115 default: 114 default:
116 ASSERT_NOT_REACHED(); 115 ASSERT_NOT_REACHED();
117 } 116 }
118 } 117 }
119 return animationData->isTimingFunctionSet() ? animationData->timingFunction( ) : CSSAnimationData::initialAnimationTimingFunction(); 118 return animationData->isTimingFunctionSet() ? animationData->timingFunction( ) : CSSAnimationData::initialAnimationTimingFunction();
120 } 119 }
121 120
121 struct TransitionDetails {
dstockwell 2013/10/09 21:03:51 CandidateTransition?
Timothy Loh 2013/10/10 02:10:19 Done.
122 TransitionDetails(PassRefPtr<AnimatableValue> from, PassRefPtr<AnimatableVal ue> to, const CSSAnimationData* anim)
123 : from(from)
124 , to(to)
125 , anim(anim)
126 {
127 }
128 TransitionDetails() { } // The HashMap calls the default ctor
129 RefPtr<AnimatableValue> from;
130 RefPtr<AnimatableValue> to;
131 const CSSAnimationData* anim;
132 };
133 typedef HashMap<CSSPropertyID, TransitionDetails> StyleChange;
dstockwell 2013/10/09 21:03:51 CandidateTransitionMap
Timothy Loh 2013/10/10 02:10:19 Done.
134
135 void updateIfPropertyChanged(const CSSAnimationData* anim, CSSPropertyID id, con st RenderStyle* oldStyle, const RenderStyle* newStyle, StyleChange& styleChange)
136 {
137 RefPtr<AnimatableValue> from = CSSAnimatableValueFactory::create(id, oldStyl e);
138 RefPtr<AnimatableValue> to = CSSAnimatableValueFactory::create(id, newStyle) ;
139 // If we have multiple transitions on the same property, we will use the
140 // last one since we iterate over them in order and this will override
141 // a previously set TransitionDetails.
142 if (!from->equals(to.get()))
143 styleChange.add(id, TransitionDetails(from, to, anim));
144 }
145
146 void computeStyleChange(const RenderStyle* oldStyle, const RenderStyle* newStyle , StyleChange& styleChange, HashSet<CSSPropertyID>& listedProperties)
147 {
148 if (!newStyle->transitions())
149 return;
150
151 for (size_t i = 0; i < newStyle->transitions()->size(); ++i) {
152 const CSSAnimationData* anim = newStyle->transitions()->animation(i);
153 CSSAnimationData::AnimationMode mode = anim->animationMode();
154 if (anim->duration() + anim->delay() <= 0 || mode == CSSAnimationData::A nimateNone)
155 continue;
156
157 bool animateAll = mode == CSSAnimationData::AnimateAll;
158 ASSERT(animateAll || mode == CSSAnimationData::AnimateSingleProperty);
159 const StylePropertyShorthand& propertyList = animateAll ? CSSAnimations: :animatableProperties() : shorthandForProperty(anim->property());
160 if (!propertyList.length()) {
161 listedProperties.add(anim->property());
162 updateIfPropertyChanged(anim, anim->property(), oldStyle, newStyle, styleChange);
163 } else {
164 for (unsigned i = 0; i < propertyList.length(); ++i) {
165 CSSPropertyID id = propertyList.properties()[i];
166 if (!animateAll && !CSSAnimations::isAnimatableProperty(id))
167 continue;
168 listedProperties.add(id);
169 updateIfPropertyChanged(anim, id, oldStyle, newStyle, styleChang e);
170 }
171 }
172 }
173 }
174
175 } // namespace
176
122 CSSAnimationUpdateScope::CSSAnimationUpdateScope(Element* target) 177 CSSAnimationUpdateScope::CSSAnimationUpdateScope(Element* target)
123 : m_target(target) 178 : m_target(target)
124 { 179 {
125 if (!m_target) 180 if (!m_target)
126 return; 181 return;
127 ActiveAnimations* activeAnimations = m_target->activeAnimations(); 182 ActiveAnimations* activeAnimations = m_target->activeAnimations();
128 CSSAnimations* cssAnimations = activeAnimations ? activeAnimations->cssAnima tions() : 0; 183 CSSAnimations* cssAnimations = activeAnimations ? activeAnimations->cssAnima tions() : 0;
129 // It's possible than an update was created outside an update scope. That's harmless 184 // It's possible than an update was created outside an update scope. That's harmless
130 // but we must clear it now to avoid applying it if an updated replacement i s not 185 // but we must clear it now to avoid applying it if an updated replacement i s not
131 // created in this scope. 186 // created in this scope.
132 if (cssAnimations) 187 if (cssAnimations)
133 cssAnimations->setPendingUpdate(nullptr); 188 cssAnimations->setPendingUpdate(nullptr);
134 } 189 }
135 190
136 CSSAnimationUpdateScope::~CSSAnimationUpdateScope() 191 CSSAnimationUpdateScope::~CSSAnimationUpdateScope()
137 { 192 {
138 if (!m_target) 193 if (!m_target)
139 return; 194 return;
140 ActiveAnimations* activeAnimations = m_target->activeAnimations(); 195 ActiveAnimations* activeAnimations = m_target->activeAnimations();
141 CSSAnimations* cssAnimations = activeAnimations ? activeAnimations->cssAnima tions() : 0; 196 CSSAnimations* cssAnimations = activeAnimations ? activeAnimations->cssAnima tions() : 0;
142 if (cssAnimations) 197 if (cssAnimations)
143 cssAnimations->maybeApplyPendingUpdate(m_target); 198 cssAnimations->maybeApplyPendingUpdate(m_target);
144 } 199 }
145 200
146 bool CSSAnimations::needsUpdate(const Element* element, const RenderStyle* style ) 201 PassOwnPtr<CSSAnimationUpdate> CSSAnimations::calculateUpdate(Element* element, const RenderStyle* style, StyleResolver* resolver)
202 {
203 ASSERT(RuntimeEnabledFeatures::webAnimationsCSSEnabled());
204 OwnPtr<CSSAnimationUpdate> update = adoptPtr(new CSSAnimationUpdate());
205 calculateAnimationUpdate(update.get(), element, style, resolver);
206 calculateTransitionUpdate(update.get(), element, style);
207 return update->isEmpty() ? nullptr : update.release();
208 }
209
210 void CSSAnimations::calculateAnimationUpdate(CSSAnimationUpdate* update, Element * element, const RenderStyle* style, StyleResolver* resolver)
147 { 211 {
148 ActiveAnimations* activeAnimations = element->activeAnimations(); 212 ActiveAnimations* activeAnimations = element->activeAnimations();
149 const CSSAnimationDataList* animations = style->animations(); 213 const CSSAnimationDataList* animationDataList = style->animations();
150 const CSSAnimations* cssAnimations = activeAnimations ? activeAnimations->cs sAnimations() : 0; 214 const CSSAnimations* cssAnimations = activeAnimations ? activeAnimations->cs sAnimations() : 0;
151 EDisplay display = style->display();
152 return (display != NONE && animations && animations->size()) || (cssAnimatio ns && !cssAnimations->isEmpty());
153 }
154 215
155 PassOwnPtr<CSSAnimationUpdate> CSSAnimations::calculateUpdate(Element* element, const RenderStyle* style, const CSSAnimations* cssAnimations, const CSSAnimation DataList* animationDataList, StyleResolver* resolver)
156 {
157 OwnPtr<CSSAnimationUpdate> update;
158 HashSet<AtomicString> inactive; 216 HashSet<AtomicString> inactive;
159 if (cssAnimations) 217 if (cssAnimations)
160 for (AnimationMap::const_iterator iter = cssAnimations->m_animations.beg in(); iter != cssAnimations->m_animations.end(); ++iter) 218 for (AnimationMap::const_iterator iter = cssAnimations->m_animations.beg in(); iter != cssAnimations->m_animations.end(); ++iter)
161 inactive.add(iter->key); 219 inactive.add(iter->key);
162 220
163 if (style->display() != NONE) { 221 if (style->display() != NONE) {
164 for (size_t i = 0; animationDataList && i < animationDataList->size(); + +i) { 222 for (size_t i = 0; animationDataList && i < animationDataList->size(); + +i) {
165 const CSSAnimationData* animationData = animationDataList->animation (i); 223 const CSSAnimationData* animationData = animationDataList->animation (i);
166 if (animationData->isNoneAnimation()) 224 if (animationData->isNoneAnimation())
167 continue; 225 continue;
168 ASSERT(animationData->isValidAnimation()); 226 ASSERT(animationData->isValidAnimation());
169 AtomicString animationName(animationData->name()); 227 AtomicString animationName(animationData->name());
170 228
171 if (cssAnimations) { 229 if (cssAnimations) {
172 AnimationMap::const_iterator existing(cssAnimations->m_animation s.find(animationName)); 230 AnimationMap::const_iterator existing(cssAnimations->m_animation s.find(animationName));
173 if (existing != cssAnimations->m_animations.end()) { 231 if (existing != cssAnimations->m_animations.end()) {
174 // FIXME: The play-state of this animation might have change d, record the change in the update. 232 // FIXME: The play-state of this animation might have change d, record the change in the update.
175 inactive.remove(animationName); 233 inactive.remove(animationName);
176 continue; 234 continue;
177 } 235 }
178 } 236 }
179 237
180 Timing timing; 238 Timing timing;
181 RefPtr<TimingFunction> defaultTimingFunction = timingFromAnimationDa ta(animationData, timing); 239 RefPtr<TimingFunction> defaultTimingFunction = timingFromAnimationDa ta(animationData, timing);
182 Vector<std::pair<KeyframeAnimationEffect::KeyframeVector, RefPtr<Tim ingFunction> > > keyframesAndTimingFunctions; 240 Vector<std::pair<KeyframeAnimationEffect::KeyframeVector, RefPtr<Tim ingFunction> > > keyframesAndTimingFunctions;
183 resolver->resolveKeyframes(element, style, animationName, defaultTim ingFunction.get(), keyframesAndTimingFunctions); 241 resolver->resolveKeyframes(element, style, animationName, defaultTim ingFunction.get(), keyframesAndTimingFunctions);
184 if (!keyframesAndTimingFunctions.isEmpty()) { 242 if (!keyframesAndTimingFunctions.isEmpty()) {
185 if (!update)
186 update = adoptPtr(new CSSAnimationUpdate());
187 HashSet<RefPtr<InertAnimation> > animations; 243 HashSet<RefPtr<InertAnimation> > animations;
188 for (size_t j = 0; j < keyframesAndTimingFunctions.size(); ++j) { 244 for (size_t j = 0; j < keyframesAndTimingFunctions.size(); ++j) {
189 ASSERT(!keyframesAndTimingFunctions[j].first.isEmpty()); 245 ASSERT(!keyframesAndTimingFunctions[j].first.isEmpty());
190 timing.timingFunction = keyframesAndTimingFunctions[j].secon d; 246 timing.timingFunction = keyframesAndTimingFunctions[j].secon d;
191 // FIXME: crbug.com/268791 - Keyframes are already normalize d, perhaps there should be a flag on KeyframeAnimationEffect to skip normalizati on. 247 // FIXME: crbug.com/268791 - Keyframes are already normalize d, perhaps there should be a flag on KeyframeAnimationEffect to skip normalizati on.
192 animations.add(InertAnimation::create(KeyframeAnimationEffec t::create(keyframesAndTimingFunctions[j].first), timing)); 248 animations.add(InertAnimation::create(KeyframeAnimationEffec t::create(keyframesAndTimingFunctions[j].first), timing));
193 } 249 }
194 update->startAnimation(animationName, animations); 250 update->startAnimation(animationName, animations);
195 } 251 }
196 } 252 }
197 } 253 }
198 254
199 if (!inactive.isEmpty() && !update)
200 update = adoptPtr(new CSSAnimationUpdate());
201 for (HashSet<AtomicString>::const_iterator iter = inactive.begin(); iter != inactive.end(); ++iter) 255 for (HashSet<AtomicString>::const_iterator iter = inactive.begin(); iter != inactive.end(); ++iter)
202 update->cancelAnimation(*iter, cssAnimations->m_animations.get(*iter)); 256 update->cancelAnimation(*iter, cssAnimations->m_animations.get(*iter));
203
204 return update.release();
205 } 257 }
206 258
207 void CSSAnimations::maybeApplyPendingUpdate(Element* element) 259 void CSSAnimations::maybeApplyPendingUpdate(Element* element)
208 { 260 {
209 if (!element->renderer()) 261 if (!element->renderer())
210 m_pendingUpdate = nullptr; 262 m_pendingUpdate = nullptr;
211 263
212 if (!m_pendingUpdate) 264 if (!m_pendingUpdate)
213 return; 265 return;
214 266
215 OwnPtr<CSSAnimationUpdate> update = m_pendingUpdate.release(); 267 OwnPtr<CSSAnimationUpdate> update = m_pendingUpdate.release();
216 268
217 for (Vector<AtomicString>::const_iterator iter = update->cancelledAnimationN ames().begin(); iter != update->cancelledAnimationNames().end(); ++iter) { 269 for (Vector<AtomicString>::const_iterator iter = update->cancelledAnimationN ames().begin(); iter != update->cancelledAnimationNames().end(); ++iter) {
218 const HashSet<RefPtr<Player> >& players = m_animations.take(*iter); 270 const HashSet<RefPtr<Player> >& players = m_animations.take(*iter);
219 for (HashSet<RefPtr<Player> >::const_iterator iter = players.begin(); it er != players.end(); ++iter) 271 for (HashSet<RefPtr<Player> >::const_iterator iter = players.begin(); it er != players.end(); ++iter)
220 (*iter)->cancel(); 272 (*iter)->cancel();
221 } 273 }
222 274
223 // FIXME: Apply updates to play-state. 275 // FIXME: Apply updates to play-state.
224 276
225 for (Vector<CSSAnimationUpdate::NewAnimation>::const_iterator iter = update- >newAnimations().begin(); iter != update->newAnimations().end(); ++iter) { 277 for (Vector<CSSAnimationUpdate::NewAnimation>::const_iterator iter = update- >newAnimations().begin(); iter != update->newAnimations().end(); ++iter) {
226 OwnPtr<CSSAnimations::EventDelegate> eventDelegate = adoptPtr(new EventD elegate(element, iter->name)); 278 OwnPtr<AnimationEventDelegate> eventDelegate = adoptPtr(new AnimationEve ntDelegate(element, iter->name));
227 HashSet<RefPtr<Player> > players; 279 HashSet<RefPtr<Player> > players;
228 for (HashSet<RefPtr<InertAnimation> >::const_iterator animationsIter = i ter->animations.begin(); animationsIter != iter->animations.end(); ++animationsI ter) { 280 for (HashSet<RefPtr<InertAnimation> >::const_iterator animationsIter = i ter->animations.begin(); animationsIter != iter->animations.end(); ++animationsI ter) {
229 const InertAnimation* inertAnimation = animationsIter->get(); 281 const InertAnimation* inertAnimation = animationsIter->get();
230 // The event delegate is set on the the first animation only. We 282 // The event delegate is set on the the first animation only. We
231 // rely on the behavior of OwnPtr::release() to achieve this. 283 // rely on the behavior of OwnPtr::release() to achieve this.
232 RefPtr<Animation> animation = Animation::create(element, inertAnimat ion->effect(), inertAnimation->specified(), eventDelegate.release()); 284 RefPtr<Animation> animation = Animation::create(element, inertAnimat ion->effect(), inertAnimation->specified(), eventDelegate.release());
233 players.add(element->document().timeline()->play(animation.get())); 285 players.add(element->document().timeline()->play(animation.get()));
234 } 286 }
235 m_animations.set(iter->name, players); 287 m_animations.set(iter->name, players);
236 } 288 }
289
290 for (HashSet<CSSPropertyID>::iterator iter = update->endedTransitions().begi n(); iter != update->endedTransitions().end(); ++iter) {
291 ASSERT(m_transitions.contains(*iter));
292 m_transitions.take(*iter).player->cancel();
293 }
294
295 for (size_t i = 0; i < update->newTransitions().size(); ++i) {
296 const CSSAnimationUpdate::NewTransition& newTransition = update->newTran sitions()[i];
297
298 RunningTransition runningTransition;
299 runningTransition.from = newTransition.from;
300 runningTransition.to = newTransition.to;
301
302 CSSPropertyID id = newTransition.id;
303 InertAnimation* inertAnimation = newTransition.animation.get();
304 OwnPtr<TransitionEventDelegate> eventDelegate = adoptPtr(new TransitionE ventDelegate(element, id));
305 RefPtr<Animation> transition = Animation::create(element, inertAnimation ->effect(), inertAnimation->specified(), eventDelegate.release());
306 // FIXME: Transitions need to be added to a separate timeline.
307 runningTransition.player = element->document().timeline()->play(transiti on.get());
308 m_transitions.set(id, runningTransition);
309 }
310 }
311
312 void CSSAnimations::calculateTransitionUpdateForProperty(CSSAnimationUpdate* upd ate, CSSPropertyID id, const AnimatableValue* from, const AnimatableValue* to, c onst CSSAnimationData* anim, const TransitionMap* transitions)
313 {
314 // FIXME: Skip the rest of this if there is a running animation on this prop erty
315
316 Timing timing;
317 RefPtr<TimingFunction> timingFunction = timingFromAnimationData(anim, timing );
318 timing.timingFunction = timingFunction;
319 timing.fillMode = Timing::FillModeBoth;
dstockwell 2013/10/09 21:03:51 We should discuss this, I'm not sure why this is n
Timothy Loh 2013/10/10 02:10:19 We still need at least FillModeBackwards so delay
320
321 if (transitions) {
322 TransitionMap::const_iterator existingTransitionIter = transitions->find (id);
323
324 if (existingTransitionIter != transitions->end() && !update->endedTransi tions().contains(id)) {
325 const AnimatableValue* existingTo = existingTransitionIter->value.to ;
326 if (existingTo->equals(to))
327 return;
328 update->endTransition(id);
329 }
330 }
331
332 KeyframeAnimationEffect::KeyframeVector keyframes;
333
334 RefPtr<Keyframe> startKeyframe = Keyframe::create();
335 startKeyframe->setPropertyValue(id, from);
336 startKeyframe->setOffset(0);
337 keyframes.append(startKeyframe);
338
339 RefPtr<Keyframe> endKeyframe = Keyframe::create();
340 endKeyframe->setPropertyValue(id, to);
341 endKeyframe->setOffset(1);
342 keyframes.append(endKeyframe);
343
344 RefPtr<KeyframeAnimationEffect> effect = KeyframeAnimationEffect::create(key frames);
345
346 update->startTransition(id, from, to, InertAnimation::create(effect, timing) );
347 }
348
349 void CSSAnimations::calculateTransitionUpdate(CSSAnimationUpdate* update, const Element* element, const RenderStyle* style)
350 {
351 ActiveAnimations* activeAnimations = element->activeAnimations();
352 const CSSAnimations* cssAnimations = activeAnimations ? activeAnimations->cs sAnimations() : 0;
353 const TransitionMap* transitions = cssAnimations ? &cssAnimations->m_transit ions : 0;
354
355 HashSet<CSSPropertyID> listedProperties;
356 if (style->display() != NONE && element->renderer() && element->renderer()-> style()) {
357 StyleChange styleChange;
358 computeStyleChange(element->renderer()->style(), style, styleChange, lis tedProperties);
359 for (StyleChange::const_iterator iter = styleChange.begin(); iter != sty leChange.end(); ++iter) {
360 CSSPropertyID id = iter->key;
dstockwell 2013/10/09 21:03:51 Inline these, there are no line limits in blink.
Timothy Loh 2013/10/10 02:10:19 Done.
361 AnimatableValue* from = iter->value.from.get();
362 AnimatableValue* to = iter->value.to.get();
363 const CSSAnimationData* anim = iter->value.anim;
364 calculateTransitionUpdateForProperty(update, id, from, to, anim, tra nsitions);
365 }
366 }
367
368 if (transitions) {
369 for (TransitionMap::const_iterator iter = transitions->begin(); iter != transitions->end(); ++iter) {
370 const TimedItem* timedItem = iter->value.player->source();
371 CSSPropertyID id = iter->key;
372 if (timedItem->phase() == TimedItem::PhaseAfter || !listedProperties .contains(id))
373 update->endTransition(id);
374 }
375 }
237 } 376 }
238 377
239 void CSSAnimations::cancel() 378 void CSSAnimations::cancel()
240 { 379 {
241 for (AnimationMap::iterator iter = m_animations.begin(); iter != m_animation s.end(); ++iter) { 380 for (AnimationMap::iterator iter = m_animations.begin(); iter != m_animation s.end(); ++iter) {
242 const HashSet<RefPtr<Player> >& players = iter->value; 381 const HashSet<RefPtr<Player> >& players = iter->value;
243 for (HashSet<RefPtr<Player> >::const_iterator animationsIter = players.b egin(); animationsIter != players.end(); ++animationsIter) 382 for (HashSet<RefPtr<Player> >::const_iterator animationsIter = players.b egin(); animationsIter != players.end(); ++animationsIter)
244 (*animationsIter)->cancel(); 383 (*animationsIter)->cancel();
245 } 384 }
246 385
386 for (TransitionMap::iterator iter = m_transitions.begin(); iter != m_transit ions.end(); ++iter)
387 iter->value.player->cancel();
388
247 m_animations.clear(); 389 m_animations.clear();
390 m_transitions.clear();
248 m_pendingUpdate = nullptr; 391 m_pendingUpdate = nullptr;
249 } 392 }
250 393
251 void CSSAnimations::EventDelegate::maybeDispatch(Document::ListenerType listener Type, const AtomicString& eventName, double elapsedTime) 394 void CSSAnimations::AnimationEventDelegate::maybeDispatch(Document::ListenerType listenerType, const AtomicString& eventName, double elapsedTime)
252 { 395 {
253 if (m_target->document().hasListenerType(listenerType)) 396 if (m_target->document().hasListenerType(listenerType))
254 m_target->document().timeline()->addEventToDispatch(m_target, WebKitAnim ationEvent::create(eventName, m_name, elapsedTime)); 397 m_target->document().timeline()->addEventToDispatch(m_target, WebKitAnim ationEvent::create(eventName, m_name, elapsedTime));
255 } 398 }
256 399
257 void CSSAnimations::EventDelegate::onEventCondition(const TimedItem* timedItem, bool isFirstSample, TimedItem::Phase previousPhase, double previousIteration) 400 void CSSAnimations::AnimationEventDelegate::onEventCondition(const TimedItem* ti medItem, bool isFirstSample, TimedItem::Phase previousPhase, double previousIter ation)
258 { 401 {
259 // Events for a single document are queued and dispatched as a group at 402 // Events for a single document are queued and dispatched as a group at
260 // the end of DocumentTimeline::serviceAnimations. 403 // the end of DocumentTimeline::serviceAnimations.
261 // FIXME: Events which are queued outside of serviceAnimations should 404 // FIXME: Events which are queued outside of serviceAnimations should
262 // trigger a timer to dispatch when control is released. 405 // trigger a timer to dispatch when control is released.
263 const TimedItem::Phase currentPhase = timedItem->phase(); 406 const TimedItem::Phase currentPhase = timedItem->phase();
264 const double currentIteration = timedItem->currentIteration(); 407 const double currentIteration = timedItem->currentIteration();
265 408
266 // Note that the elapsedTime is measured from when the animation starts play ing. 409 // Note that the elapsedTime is measured from when the animation starts play ing.
267 if (!isFirstSample && previousPhase == TimedItem::PhaseActive && currentPhas e == TimedItem::PhaseActive && previousIteration != currentIteration) { 410 if (!isFirstSample && previousPhase == TimedItem::PhaseActive && currentPhas e == TimedItem::PhaseActive && previousIteration != currentIteration) {
(...skipping 12 matching lines...) Expand all
280 ASSERT(timedItem->specified().startDelay > 0 || isFirstSample); 423 ASSERT(timedItem->specified().startDelay > 0 || isFirstSample);
281 // The spec states that the elapsed time should be 424 // The spec states that the elapsed time should be
282 // 'delay < 0 ? -delay : 0', but we always use 0 to match the existing 425 // 'delay < 0 ? -delay : 0', but we always use 0 to match the existing
283 // implementation. See crbug.com/279611 426 // implementation. See crbug.com/279611
284 maybeDispatch(Document::ANIMATIONSTART_LISTENER, EventNames::animationst art, 0); 427 maybeDispatch(Document::ANIMATIONSTART_LISTENER, EventNames::animationst art, 0);
285 } 428 }
286 if ((isFirstSample || isEarlierPhase(previousPhase, TimedItem::PhaseAfter)) && currentPhase == TimedItem::PhaseAfter) 429 if ((isFirstSample || isEarlierPhase(previousPhase, TimedItem::PhaseAfter)) && currentPhase == TimedItem::PhaseAfter)
287 maybeDispatch(Document::ANIMATIONEND_LISTENER, EventNames::animationend, timedItem->activeDuration()); 430 maybeDispatch(Document::ANIMATIONEND_LISTENER, EventNames::animationend, timedItem->activeDuration());
288 } 431 }
289 432
433 void CSSAnimations::TransitionEventDelegate::onEventCondition(const TimedItem* t imedItem, bool isFirstSample, TimedItem::Phase previousPhase, double previousIte ration)
434 {
435 // Events for a single document are queued and dispatched as a group at
436 // the end of DocumentTimeline::serviceAnimations.
437 // FIXME: Events which are queued outside of serviceAnimations should
438 // trigger a timer to dispatch when control is released.
439 const TimedItem::Phase currentPhase = timedItem->phase();
440 if (currentPhase == TimedItem::PhaseAfter && (isFirstSample || previousPhase != currentPhase)) {
441 if (m_target->document().hasListenerType(Document::TRANSITIONEND_LISTENE R)) {
442 String propertyName = getPropertyNameString(m_property);
443 const Timing& timing = timedItem->specified();
444 double elapsedTime = timing.iterationDuration;
445 const AtomicString& eventType = EventNames::transitionend;
446 String pseudoElement = PseudoElement::pseudoElementNameForEvents(m_t arget->pseudoId());
447 m_target->document().timeline()->addEventToDispatch(m_target, Transi tionEvent::create(eventType, propertyName, elapsedTime, pseudoElement));
448 }
449 }
450 }
451
452
290 bool CSSAnimations::isAnimatableProperty(CSSPropertyID property) 453 bool CSSAnimations::isAnimatableProperty(CSSPropertyID property)
291 { 454 {
292 switch (property) { 455 switch (property) {
293 case CSSPropertyBackgroundColor: 456 case CSSPropertyBackgroundColor:
294 case CSSPropertyBackgroundImage: 457 case CSSPropertyBackgroundImage:
295 case CSSPropertyBackgroundPositionX: 458 case CSSPropertyBackgroundPositionX:
296 case CSSPropertyBackgroundPositionY: 459 case CSSPropertyBackgroundPositionY:
297 case CSSPropertyBackgroundSize: 460 case CSSPropertyBackgroundSize:
298 case CSSPropertyBaselineShift: 461 case CSSPropertyBaselineShift:
299 case CSSPropertyBorderBottomColor: 462 case CSSPropertyBorderBottomColor:
(...skipping 14 matching lines...) Expand all
314 case CSSPropertyBorderTopWidth: 477 case CSSPropertyBorderTopWidth:
315 case CSSPropertyBottom: 478 case CSSPropertyBottom:
316 case CSSPropertyBoxShadow: 479 case CSSPropertyBoxShadow:
317 case CSSPropertyClip: 480 case CSSPropertyClip:
318 case CSSPropertyColor: 481 case CSSPropertyColor:
319 case CSSPropertyFill: 482 case CSSPropertyFill:
320 case CSSPropertyFillOpacity: 483 case CSSPropertyFillOpacity:
321 // FIXME: Shorthands should not be present in this list, but 484 // FIXME: Shorthands should not be present in this list, but
322 // CSSPropertyAnimation implements animation of flex directly and 485 // CSSPropertyAnimation implements animation of flex directly and
323 // makes use of this method. 486 // makes use of this method.
324 case CSSPropertyFlex: 487 case CSSPropertyFlex:
dstockwell 2013/10/09 21:03:51 Do we need to special case this for 'all'?
Timothy Loh 2013/10/10 02:10:19 Looks like it. Good catch.
325 case CSSPropertyFlexBasis: 488 case CSSPropertyFlexBasis:
326 case CSSPropertyFlexGrow: 489 case CSSPropertyFlexGrow:
327 case CSSPropertyFlexShrink: 490 case CSSPropertyFlexShrink:
328 case CSSPropertyFloodColor: 491 case CSSPropertyFloodColor:
329 case CSSPropertyFloodOpacity: 492 case CSSPropertyFloodOpacity:
330 case CSSPropertyFontSize: 493 case CSSPropertyFontSize:
331 case CSSPropertyHeight: 494 case CSSPropertyHeight:
332 case CSSPropertyKerning: 495 case CSSPropertyKerning:
333 case CSSPropertyLeft: 496 case CSSPropertyLeft:
334 case CSSPropertyLetterSpacing: 497 case CSSPropertyLetterSpacing:
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
397 case CSSPropertyWidth: 560 case CSSPropertyWidth:
398 case CSSPropertyWordSpacing: 561 case CSSPropertyWordSpacing:
399 case CSSPropertyZIndex: 562 case CSSPropertyZIndex:
400 case CSSPropertyZoom: 563 case CSSPropertyZoom:
401 return true; 564 return true;
402 default: 565 default:
403 return false; 566 return false;
404 } 567 }
405 } 568 }
406 569
570 const StylePropertyShorthand& CSSAnimations::animatableProperties()
571 {
572 DEFINE_STATIC_LOCAL(Vector<CSSPropertyID>, properties, ());
573 DEFINE_STATIC_LOCAL(StylePropertyShorthand, propertyShorthand, ());
574 if (properties.isEmpty()) {
575 for (int i = firstCSSProperty; i < lastCSSProperty; ++i) {
576 CSSPropertyID id = convertToCSSPropertyID(i);
577 if (isAnimatableProperty(id))
578 properties.append(id);
579 }
580 propertyShorthand = StylePropertyShorthand(CSSPropertyInvalid, propertie s.begin(), properties.size());
581 }
582 return propertyShorthand;
583 }
584
407 } // namespace WebCore 585 } // namespace WebCore
OLDNEW
« no previous file with comments | « Source/core/animation/css/CSSAnimations.h ('k') | Source/core/css/resolver/StyleAdjuster.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698