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

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: added comment for fill mode ; rebased 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
51 struct CandidateTransition {
52 CandidateTransition(PassRefPtr<AnimatableValue> from, PassRefPtr<AnimatableV alue> to, const CSSAnimationData* anim)
53 : from(from)
54 , to(to)
55 , anim(anim)
56 {
57 }
58 CandidateTransition() { } // The HashMap calls the default ctor
59 RefPtr<AnimatableValue> from;
60 RefPtr<AnimatableValue> to;
61 const CSSAnimationData* anim;
62 };
63 typedef HashMap<CSSPropertyID, CandidateTransition> CandidateTransitionMap;
64
46 namespace { 65 namespace {
47 66
48 using namespace WebCore;
49
50 bool isEarlierPhase(TimedItem::Phase target, TimedItem::Phase reference) 67 bool isEarlierPhase(TimedItem::Phase target, TimedItem::Phase reference)
51 { 68 {
52 ASSERT(target != TimedItem::PhaseNone); 69 ASSERT(target != TimedItem::PhaseNone);
53 ASSERT(reference != TimedItem::PhaseNone); 70 ASSERT(reference != TimedItem::PhaseNone);
54 return target < reference; 71 return target < reference;
55 } 72 }
56 73
57 bool isLaterPhase(TimedItem::Phase target, TimedItem::Phase reference) 74 bool isLaterPhase(TimedItem::Phase target, TimedItem::Phase reference)
58 { 75 {
59 ASSERT(target != TimedItem::PhaseNone); 76 ASSERT(target != TimedItem::PhaseNone);
60 ASSERT(reference != TimedItem::PhaseNone); 77 ASSERT(reference != TimedItem::PhaseNone);
61 return target > reference; 78 return target > reference;
62 } 79 }
63 80
64 } // namespace
65
66 namespace WebCore {
67
68 // Returns the default timing function. 81 // Returns the default timing function.
69 const PassRefPtr<TimingFunction> timingFromAnimationData(const CSSAnimationData* animationData, Timing& timing) 82 const PassRefPtr<TimingFunction> timingFromAnimationData(const CSSAnimationData* animationData, Timing& timing)
70 { 83 {
71 if (animationData->isDelaySet()) 84 if (animationData->isDelaySet())
72 timing.startDelay = animationData->delay(); 85 timing.startDelay = animationData->delay();
73 if (animationData->isDurationSet()) { 86 if (animationData->isDurationSet()) {
74 timing.iterationDuration = animationData->duration(); 87 timing.iterationDuration = animationData->duration();
75 timing.hasIterationDuration = true; 88 timing.hasIterationDuration = true;
76 } 89 }
77 if (animationData->isIterationCountSet()) { 90 if (animationData->isIterationCountSet()) {
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
114 case CSSAnimationData::AnimationDirectionAlternateReverse: 127 case CSSAnimationData::AnimationDirectionAlternateReverse:
115 timing.direction = Timing::PlaybackDirectionAlternateReverse; 128 timing.direction = Timing::PlaybackDirectionAlternateReverse;
116 break; 129 break;
117 default: 130 default:
118 ASSERT_NOT_REACHED(); 131 ASSERT_NOT_REACHED();
119 } 132 }
120 } 133 }
121 return animationData->isTimingFunctionSet() ? animationData->timingFunction( ) : CSSAnimationData::initialAnimationTimingFunction(); 134 return animationData->isTimingFunctionSet() ? animationData->timingFunction( ) : CSSAnimationData::initialAnimationTimingFunction();
122 } 135 }
123 136
137 void updateIfPropertyChanged(const CSSAnimationData* anim, CSSPropertyID id, con st RenderStyle* oldStyle, const RenderStyle* newStyle, CandidateTransitionMap& s tyleChange)
dstockwell 2013/10/14 00:05:21 calculateCandidateTransitionForProperty
dstockwell 2013/10/14 00:05:21 styleChange -> candidateMap throughout
Timothy Loh 2013/10/14 00:32:27 Done.
Timothy Loh 2013/10/14 00:32:27 Done.
138 {
139 RefPtr<AnimatableValue> from = CSSAnimatableValueFactory::create(id, oldStyl e);
140 RefPtr<AnimatableValue> to = CSSAnimatableValueFactory::create(id, newStyle) ;
141 // If we have multiple transitions on the same property, we will use the
142 // last one since we iterate over them in order and this will override
143 // a previously set CandidateTransition.
144 if (!from->equals(to.get()))
145 styleChange.add(id, CandidateTransition(from, to, anim));
Steve Block 2013/10/13 23:58:20 You should call release() on 'from' and 'to' here
Timothy Loh 2013/10/14 00:32:27 Done. Didn't know about these before :)
146 }
147
148 void computeStyleChange(const RenderStyle* oldStyle, const RenderStyle* newStyle , CandidateTransitionMap& styleChange, HashSet<CSSPropertyID>& listedProperties)
dstockwell 2013/10/14 00:05:21 calculateCandidateTransitions
Timothy Loh 2013/10/14 00:32:27 Done.
149 {
150 if (!newStyle->transitions())
151 return;
152
153 for (size_t i = 0; i < newStyle->transitions()->size(); ++i) {
154 const CSSAnimationData* anim = newStyle->transitions()->animation(i);
155 CSSAnimationData::AnimationMode mode = anim->animationMode();
156 if (anim->duration() + anim->delay() <= 0 || mode == CSSAnimationData::A nimateNone)
157 continue;
158
159 bool animateAll = mode == CSSAnimationData::AnimateAll;
160 ASSERT(animateAll || mode == CSSAnimationData::AnimateSingleProperty);
161 const StylePropertyShorthand& propertyList = animateAll ? CSSAnimations: :animatableProperties() : shorthandForProperty(anim->property());
162 if (!propertyList.length()) {
163 listedProperties.add(anim->property());
164 updateIfPropertyChanged(anim, anim->property(), oldStyle, newStyle, styleChange);
165 } else {
166 for (unsigned i = 0; i < propertyList.length(); ++i) {
167 CSSPropertyID id = propertyList.properties()[i];
168 if (!animateAll && !CSSAnimations::isAnimatableProperty(id))
169 continue;
170 listedProperties.add(id);
171 updateIfPropertyChanged(anim, id, oldStyle, newStyle, styleChang e);
172 }
173 }
174 }
175 }
176
177 } // namespace
178
124 CSSAnimationUpdateScope::CSSAnimationUpdateScope(Element* target) 179 CSSAnimationUpdateScope::CSSAnimationUpdateScope(Element* target)
125 : m_target(target) 180 : m_target(target)
126 { 181 {
127 if (!m_target) 182 if (!m_target)
128 return; 183 return;
129 ActiveAnimations* activeAnimations = m_target->activeAnimations(); 184 ActiveAnimations* activeAnimations = m_target->activeAnimations();
130 CSSAnimations* cssAnimations = activeAnimations ? activeAnimations->cssAnima tions() : 0; 185 CSSAnimations* cssAnimations = activeAnimations ? activeAnimations->cssAnima tions() : 0;
131 // It's possible than an update was created outside an update scope. That's harmless 186 // It's possible than an update was created outside an update scope. That's harmless
132 // but we must clear it now to avoid applying it if an updated replacement i s not 187 // but we must clear it now to avoid applying it if an updated replacement i s not
133 // created in this scope. 188 // created in this scope.
134 if (cssAnimations) 189 if (cssAnimations)
135 cssAnimations->setPendingUpdate(nullptr); 190 cssAnimations->setPendingUpdate(nullptr);
136 } 191 }
137 192
138 CSSAnimationUpdateScope::~CSSAnimationUpdateScope() 193 CSSAnimationUpdateScope::~CSSAnimationUpdateScope()
139 { 194 {
140 if (!m_target) 195 if (!m_target)
141 return; 196 return;
142 ActiveAnimations* activeAnimations = m_target->activeAnimations(); 197 ActiveAnimations* activeAnimations = m_target->activeAnimations();
143 CSSAnimations* cssAnimations = activeAnimations ? activeAnimations->cssAnima tions() : 0; 198 CSSAnimations* cssAnimations = activeAnimations ? activeAnimations->cssAnima tions() : 0;
144 if (cssAnimations) 199 if (cssAnimations)
145 cssAnimations->maybeApplyPendingUpdate(m_target); 200 cssAnimations->maybeApplyPendingUpdate(m_target);
146 } 201 }
147 202
148 bool CSSAnimations::needsUpdate(const Element* element, const RenderStyle* style ) 203 PassOwnPtr<CSSAnimationUpdate> CSSAnimations::calculateUpdate(Element* element, const RenderStyle* style, StyleResolver* resolver)
204 {
205 ASSERT(RuntimeEnabledFeatures::webAnimationsCSSEnabled());
206 OwnPtr<CSSAnimationUpdate> update = adoptPtr(new CSSAnimationUpdate());
207 calculateAnimationUpdate(update.get(), element, style, resolver);
208 calculateTransitionUpdate(update.get(), element, style);
209 return update->isEmpty() ? nullptr : update.release();
210 }
211
212 void CSSAnimations::calculateAnimationUpdate(CSSAnimationUpdate* update, Element * element, const RenderStyle* style, StyleResolver* resolver)
149 { 213 {
150 ActiveAnimations* activeAnimations = element->activeAnimations(); 214 ActiveAnimations* activeAnimations = element->activeAnimations();
151 const CSSAnimationDataList* animations = style->animations(); 215 const CSSAnimationDataList* animationDataList = style->animations();
152 const CSSAnimations* cssAnimations = activeAnimations ? activeAnimations->cs sAnimations() : 0; 216 const CSSAnimations* cssAnimations = activeAnimations ? activeAnimations->cs sAnimations() : 0;
153 EDisplay display = style->display();
154 return (display != NONE && animations && animations->size()) || (cssAnimatio ns && !cssAnimations->isEmpty());
155 }
156 217
157 PassOwnPtr<CSSAnimationUpdate> CSSAnimations::calculateUpdate(Element* element, const RenderStyle* style, const CSSAnimations* cssAnimations, const CSSAnimation DataList* animationDataList, StyleResolver* resolver)
158 {
159 OwnPtr<CSSAnimationUpdate> update;
160 HashSet<AtomicString> inactive; 218 HashSet<AtomicString> inactive;
161 if (cssAnimations) 219 if (cssAnimations)
162 for (AnimationMap::const_iterator iter = cssAnimations->m_animations.beg in(); iter != cssAnimations->m_animations.end(); ++iter) 220 for (AnimationMap::const_iterator iter = cssAnimations->m_animations.beg in(); iter != cssAnimations->m_animations.end(); ++iter)
163 inactive.add(iter->key); 221 inactive.add(iter->key);
164 222
165 if (style->display() != NONE) { 223 if (style->display() != NONE) {
166 for (size_t i = 0; animationDataList && i < animationDataList->size(); + +i) { 224 for (size_t i = 0; animationDataList && i < animationDataList->size(); + +i) {
167 const CSSAnimationData* animationData = animationDataList->animation (i); 225 const CSSAnimationData* animationData = animationDataList->animation (i);
168 if (animationData->isNoneAnimation()) 226 if (animationData->isNoneAnimation())
169 continue; 227 continue;
170 ASSERT(animationData->isValidAnimation()); 228 ASSERT(animationData->isValidAnimation());
171 AtomicString animationName(animationData->name()); 229 AtomicString animationName(animationData->name());
172 230
173 if (cssAnimations) { 231 if (cssAnimations) {
174 AnimationMap::const_iterator existing(cssAnimations->m_animation s.find(animationName)); 232 AnimationMap::const_iterator existing(cssAnimations->m_animation s.find(animationName));
175 if (existing != cssAnimations->m_animations.end()) { 233 if (existing != cssAnimations->m_animations.end()) {
176 // FIXME: The play-state of this animation might have change d, record the change in the update. 234 // FIXME: The play-state of this animation might have change d, record the change in the update.
177 inactive.remove(animationName); 235 inactive.remove(animationName);
178 continue; 236 continue;
179 } 237 }
180 } 238 }
181 239
182 Timing timing; 240 Timing timing;
183 RefPtr<TimingFunction> defaultTimingFunction = timingFromAnimationDa ta(animationData, timing); 241 RefPtr<TimingFunction> defaultTimingFunction = timingFromAnimationDa ta(animationData, timing);
184 Vector<std::pair<KeyframeAnimationEffect::KeyframeVector, RefPtr<Tim ingFunction> > > keyframesAndTimingFunctions; 242 Vector<std::pair<KeyframeAnimationEffect::KeyframeVector, RefPtr<Tim ingFunction> > > keyframesAndTimingFunctions;
185 resolver->resolveKeyframes(element, style, animationName, defaultTim ingFunction.get(), keyframesAndTimingFunctions); 243 resolver->resolveKeyframes(element, style, animationName, defaultTim ingFunction.get(), keyframesAndTimingFunctions);
186 if (!keyframesAndTimingFunctions.isEmpty()) { 244 if (!keyframesAndTimingFunctions.isEmpty()) {
187 if (!update)
188 update = adoptPtr(new CSSAnimationUpdate());
189 HashSet<RefPtr<InertAnimation> > animations; 245 HashSet<RefPtr<InertAnimation> > animations;
190 for (size_t j = 0; j < keyframesAndTimingFunctions.size(); ++j) { 246 for (size_t j = 0; j < keyframesAndTimingFunctions.size(); ++j) {
191 ASSERT(!keyframesAndTimingFunctions[j].first.isEmpty()); 247 ASSERT(!keyframesAndTimingFunctions[j].first.isEmpty());
192 timing.timingFunction = keyframesAndTimingFunctions[j].secon d; 248 timing.timingFunction = keyframesAndTimingFunctions[j].secon d;
193 // FIXME: crbug.com/268791 - Keyframes are already normalize d, perhaps there should be a flag on KeyframeAnimationEffect to skip normalizati on. 249 // FIXME: crbug.com/268791 - Keyframes are already normalize d, perhaps there should be a flag on KeyframeAnimationEffect to skip normalizati on.
194 animations.add(InertAnimation::create(KeyframeAnimationEffec t::create(keyframesAndTimingFunctions[j].first), timing)); 250 animations.add(InertAnimation::create(KeyframeAnimationEffec t::create(keyframesAndTimingFunctions[j].first), timing));
195 } 251 }
196 update->startAnimation(animationName, animations); 252 update->startAnimation(animationName, animations);
197 } 253 }
198 } 254 }
199 } 255 }
200 256
201 if (!inactive.isEmpty() && !update)
202 update = adoptPtr(new CSSAnimationUpdate());
203 for (HashSet<AtomicString>::const_iterator iter = inactive.begin(); iter != inactive.end(); ++iter) 257 for (HashSet<AtomicString>::const_iterator iter = inactive.begin(); iter != inactive.end(); ++iter)
204 update->cancelAnimation(*iter, cssAnimations->m_animations.get(*iter)); 258 update->cancelAnimation(*iter, cssAnimations->m_animations.get(*iter));
205
206 return update.release();
207 } 259 }
208 260
209 void CSSAnimations::maybeApplyPendingUpdate(Element* element) 261 void CSSAnimations::maybeApplyPendingUpdate(Element* element)
210 { 262 {
211 if (!element->renderer()) 263 if (!element->renderer())
212 m_pendingUpdate = nullptr; 264 m_pendingUpdate = nullptr;
213 265
214 if (!m_pendingUpdate) 266 if (!m_pendingUpdate)
215 return; 267 return;
216 268
217 OwnPtr<CSSAnimationUpdate> update = m_pendingUpdate.release(); 269 OwnPtr<CSSAnimationUpdate> update = m_pendingUpdate.release();
218 270
219 for (Vector<AtomicString>::const_iterator iter = update->cancelledAnimationN ames().begin(); iter != update->cancelledAnimationNames().end(); ++iter) { 271 for (Vector<AtomicString>::const_iterator iter = update->cancelledAnimationN ames().begin(); iter != update->cancelledAnimationNames().end(); ++iter) {
220 const HashSet<RefPtr<Player> >& players = m_animations.take(*iter); 272 const HashSet<RefPtr<Player> >& players = m_animations.take(*iter);
221 for (HashSet<RefPtr<Player> >::const_iterator iter = players.begin(); it er != players.end(); ++iter) 273 for (HashSet<RefPtr<Player> >::const_iterator iter = players.begin(); it er != players.end(); ++iter)
222 (*iter)->cancel(); 274 (*iter)->cancel();
223 } 275 }
224 276
225 // FIXME: Apply updates to play-state. 277 // FIXME: Apply updates to play-state.
226 278
227 for (Vector<CSSAnimationUpdate::NewAnimation>::const_iterator iter = update- >newAnimations().begin(); iter != update->newAnimations().end(); ++iter) { 279 for (Vector<CSSAnimationUpdate::NewAnimation>::const_iterator iter = update- >newAnimations().begin(); iter != update->newAnimations().end(); ++iter) {
228 OwnPtr<CSSAnimations::EventDelegate> eventDelegate = adoptPtr(new EventD elegate(element, iter->name)); 280 OwnPtr<AnimationEventDelegate> eventDelegate = adoptPtr(new AnimationEve ntDelegate(element, iter->name));
229 HashSet<RefPtr<Player> > players; 281 HashSet<RefPtr<Player> > players;
230 for (HashSet<RefPtr<InertAnimation> >::const_iterator animationsIter = i ter->animations.begin(); animationsIter != iter->animations.end(); ++animationsI ter) { 282 for (HashSet<RefPtr<InertAnimation> >::const_iterator animationsIter = i ter->animations.begin(); animationsIter != iter->animations.end(); ++animationsI ter) {
231 const InertAnimation* inertAnimation = animationsIter->get(); 283 const InertAnimation* inertAnimation = animationsIter->get();
232 // The event delegate is set on the the first animation only. We 284 // The event delegate is set on the the first animation only. We
233 // rely on the behavior of OwnPtr::release() to achieve this. 285 // rely on the behavior of OwnPtr::release() to achieve this.
234 RefPtr<Animation> animation = Animation::create(element, inertAnimat ion->effect(), inertAnimation->specified(), eventDelegate.release()); 286 RefPtr<Animation> animation = Animation::create(element, inertAnimat ion->effect(), inertAnimation->specified(), eventDelegate.release());
235 players.add(element->document().timeline()->play(animation.get())); 287 players.add(element->document().timeline()->play(animation.get()));
236 } 288 }
237 m_animations.set(iter->name, players); 289 m_animations.set(iter->name, players);
238 } 290 }
291
292 for (HashSet<CSSPropertyID>::iterator iter = update->cancelledTransitions(). begin(); iter != update->cancelledTransitions().end(); ++iter) {
293 ASSERT(m_transitions.contains(*iter));
294 m_transitions.take(*iter).player->cancel();
295 }
296
297 for (size_t i = 0; i < update->newTransitions().size(); ++i) {
298 const CSSAnimationUpdate::NewTransition& newTransition = update->newTran sitions()[i];
299
300 RunningTransition runningTransition;
301 runningTransition.from = newTransition.from;
302 runningTransition.to = newTransition.to;
303
304 CSSPropertyID id = newTransition.id;
305 InertAnimation* inertAnimation = newTransition.animation.get();
306 OwnPtr<TransitionEventDelegate> eventDelegate = adoptPtr(new TransitionE ventDelegate(element, id));
307 RefPtr<Animation> transition = Animation::create(element, inertAnimation ->effect(), inertAnimation->specified(), eventDelegate.release());
308 // FIXME: Transitions need to be added to a separate timeline.
309 runningTransition.player = element->document().timeline()->play(transiti on.get());
310 m_transitions.set(id, runningTransition);
311 }
312 }
313
314 void CSSAnimations::calculateTransitionUpdateForProperty(CSSAnimationUpdate* upd ate, CSSPropertyID id, const CandidateTransition& newTransition, const Transitio nMap* transitions)
Steve Block 2013/10/13 23:58:20 s/transitions/existingTransitions ?
Timothy Loh 2013/10/14 00:32:27 Done.
315 {
316 // FIXME: Skip the rest of this if there is a running animation on this prop erty
317
318 if (transitions) {
319 TransitionMap::const_iterator existingTransitionIter = transitions->find (id);
320
321 if (existingTransitionIter != transitions->end() && !update->cancelledTr ansitions().contains(id)) {
322 const AnimatableValue* existingTo = existingTransitionIter->value.to ;
323 if (newTransition.to->equals(existingTo))
324 return;
325 update->cancelTransition(id);
326 }
327 }
328
329 KeyframeAnimationEffect::KeyframeVector keyframes;
330
331 RefPtr<Keyframe> startKeyframe = Keyframe::create();
332 startKeyframe->setPropertyValue(id, newTransition.from.get());
333 startKeyframe->setOffset(0);
334 keyframes.append(startKeyframe);
335
336 RefPtr<Keyframe> endKeyframe = Keyframe::create();
337 endKeyframe->setPropertyValue(id, newTransition.to.get());
338 endKeyframe->setOffset(1);
339 keyframes.append(endKeyframe);
340
341 RefPtr<KeyframeAnimationEffect> effect = KeyframeAnimationEffect::create(key frames);
342
343 Timing timing;
344 RefPtr<TimingFunction> timingFunction = timingFromAnimationData(newTransitio n.anim, timing);
345 timing.timingFunction = timingFunction;
346 // Note that the backwards part is required for delay to work.
347 timing.fillMode = Timing::FillModeBoth;
348
349 update->startTransition(id, newTransition.from.get(), newTransition.to.get() , InertAnimation::create(effect, timing));
350 }
351
352 void CSSAnimations::calculateTransitionUpdate(CSSAnimationUpdate* update, const Element* element, const RenderStyle* style)
353 {
354 ActiveAnimations* activeAnimations = element->activeAnimations();
355 const CSSAnimations* cssAnimations = activeAnimations ? activeAnimations->cs sAnimations() : 0;
356 const TransitionMap* transitions = cssAnimations ? &cssAnimations->m_transit ions : 0;
357
358 HashSet<CSSPropertyID> listedProperties;
359 if (style->display() != NONE && element->renderer() && element->renderer()-> style()) {
360 CandidateTransitionMap styleChange;
361 computeStyleChange(element->renderer()->style(), style, styleChange, lis tedProperties);
362 for (CandidateTransitionMap::const_iterator iter = styleChange.begin(); iter != styleChange.end(); ++iter)
363 calculateTransitionUpdateForProperty(update, iter->key, iter->value, transitions);
364 }
365
366 if (transitions) {
367 for (TransitionMap::const_iterator iter = transitions->begin(); iter != transitions->end(); ++iter) {
368 const TimedItem* timedItem = iter->value.player->source();
369 CSSPropertyID id = iter->key;
370 if (timedItem->phase() == TimedItem::PhaseAfter || !listedProperties .contains(id))
371 update->cancelTransition(id);
372 }
373 }
239 } 374 }
240 375
241 void CSSAnimations::cancel() 376 void CSSAnimations::cancel()
242 { 377 {
243 for (AnimationMap::iterator iter = m_animations.begin(); iter != m_animation s.end(); ++iter) { 378 for (AnimationMap::iterator iter = m_animations.begin(); iter != m_animation s.end(); ++iter) {
244 const HashSet<RefPtr<Player> >& players = iter->value; 379 const HashSet<RefPtr<Player> >& players = iter->value;
245 for (HashSet<RefPtr<Player> >::const_iterator animationsIter = players.b egin(); animationsIter != players.end(); ++animationsIter) 380 for (HashSet<RefPtr<Player> >::const_iterator animationsIter = players.b egin(); animationsIter != players.end(); ++animationsIter)
246 (*animationsIter)->cancel(); 381 (*animationsIter)->cancel();
247 } 382 }
248 383
384 for (TransitionMap::iterator iter = m_transitions.begin(); iter != m_transit ions.end(); ++iter)
385 iter->value.player->cancel();
386
249 m_animations.clear(); 387 m_animations.clear();
388 m_transitions.clear();
250 m_pendingUpdate = nullptr; 389 m_pendingUpdate = nullptr;
251 } 390 }
252 391
253 void CSSAnimations::EventDelegate::maybeDispatch(Document::ListenerType listener Type, const AtomicString& eventName, double elapsedTime) 392 void CSSAnimations::AnimationEventDelegate::maybeDispatch(Document::ListenerType listenerType, const AtomicString& eventName, double elapsedTime)
254 { 393 {
255 if (m_target->document().hasListenerType(listenerType)) 394 if (m_target->document().hasListenerType(listenerType))
256 m_target->document().timeline()->addEventToDispatch(m_target, WebKitAnim ationEvent::create(eventName, m_name, elapsedTime)); 395 m_target->document().timeline()->addEventToDispatch(m_target, WebKitAnim ationEvent::create(eventName, m_name, elapsedTime));
257 } 396 }
258 397
259 void CSSAnimations::EventDelegate::onEventCondition(const TimedItem* timedItem, bool isFirstSample, TimedItem::Phase previousPhase, double previousIteration) 398 void CSSAnimations::AnimationEventDelegate::onEventCondition(const TimedItem* ti medItem, bool isFirstSample, TimedItem::Phase previousPhase, double previousIter ation)
260 { 399 {
261 // Events for a single document are queued and dispatched as a group at 400 // Events for a single document are queued and dispatched as a group at
262 // the end of DocumentTimeline::serviceAnimations. 401 // the end of DocumentTimeline::serviceAnimations.
263 // FIXME: Events which are queued outside of serviceAnimations should 402 // FIXME: Events which are queued outside of serviceAnimations should
264 // trigger a timer to dispatch when control is released. 403 // trigger a timer to dispatch when control is released.
265 const TimedItem::Phase currentPhase = timedItem->phase(); 404 const TimedItem::Phase currentPhase = timedItem->phase();
266 const double currentIteration = timedItem->currentIteration(); 405 const double currentIteration = timedItem->currentIteration();
267 406
268 // Note that the elapsedTime is measured from when the animation starts play ing. 407 // Note that the elapsedTime is measured from when the animation starts play ing.
269 if (!isFirstSample && previousPhase == TimedItem::PhaseActive && currentPhas e == TimedItem::PhaseActive && previousIteration != currentIteration) { 408 if (!isFirstSample && previousPhase == TimedItem::PhaseActive && currentPhas e == TimedItem::PhaseActive && previousIteration != currentIteration) {
(...skipping 12 matching lines...) Expand all
282 ASSERT(timedItem->specified().startDelay > 0 || isFirstSample); 421 ASSERT(timedItem->specified().startDelay > 0 || isFirstSample);
283 // The spec states that the elapsed time should be 422 // The spec states that the elapsed time should be
284 // 'delay < 0 ? -delay : 0', but we always use 0 to match the existing 423 // 'delay < 0 ? -delay : 0', but we always use 0 to match the existing
285 // implementation. See crbug.com/279611 424 // implementation. See crbug.com/279611
286 maybeDispatch(Document::ANIMATIONSTART_LISTENER, EventNames::animationst art, 0); 425 maybeDispatch(Document::ANIMATIONSTART_LISTENER, EventNames::animationst art, 0);
287 } 426 }
288 if ((isFirstSample || isEarlierPhase(previousPhase, TimedItem::PhaseAfter)) && currentPhase == TimedItem::PhaseAfter) 427 if ((isFirstSample || isEarlierPhase(previousPhase, TimedItem::PhaseAfter)) && currentPhase == TimedItem::PhaseAfter)
289 maybeDispatch(Document::ANIMATIONEND_LISTENER, EventNames::animationend, timedItem->activeDuration()); 428 maybeDispatch(Document::ANIMATIONEND_LISTENER, EventNames::animationend, timedItem->activeDuration());
290 } 429 }
291 430
431 void CSSAnimations::TransitionEventDelegate::onEventCondition(const TimedItem* t imedItem, bool isFirstSample, TimedItem::Phase previousPhase, double previousIte ration)
432 {
433 // Events for a single document are queued and dispatched as a group at
434 // the end of DocumentTimeline::serviceAnimations.
435 // FIXME: Events which are queued outside of serviceAnimations should
436 // trigger a timer to dispatch when control is released.
437 const TimedItem::Phase currentPhase = timedItem->phase();
438 if (currentPhase == TimedItem::PhaseAfter && (isFirstSample || previousPhase != currentPhase)) {
439 if (m_target->document().hasListenerType(Document::TRANSITIONEND_LISTENE R)) {
Steve Block 2013/10/13 23:58:20 These could be a single 'if'
Timothy Loh 2013/10/14 00:32:27 Done.
440 String propertyName = getPropertyNameString(m_property);
441 const Timing& timing = timedItem->specified();
442 double elapsedTime = timing.iterationDuration;
443 const AtomicString& eventType = EventNames::transitionend;
444 String pseudoElement = PseudoElement::pseudoElementNameForEvents(m_t arget->pseudoId());
445 m_target->document().timeline()->addEventToDispatch(m_target, Transi tionEvent::create(eventType, propertyName, elapsedTime, pseudoElement));
446 }
447 }
448 }
449
450
292 bool CSSAnimations::isAnimatableProperty(CSSPropertyID property) 451 bool CSSAnimations::isAnimatableProperty(CSSPropertyID property)
293 { 452 {
294 switch (property) { 453 switch (property) {
295 case CSSPropertyBackgroundColor: 454 case CSSPropertyBackgroundColor:
296 case CSSPropertyBackgroundImage: 455 case CSSPropertyBackgroundImage:
297 case CSSPropertyBackgroundPositionX: 456 case CSSPropertyBackgroundPositionX:
298 case CSSPropertyBackgroundPositionY: 457 case CSSPropertyBackgroundPositionY:
299 case CSSPropertyBackgroundSize: 458 case CSSPropertyBackgroundSize:
300 case CSSPropertyBaselineShift: 459 case CSSPropertyBaselineShift:
301 case CSSPropertyBorderBottomColor: 460 case CSSPropertyBorderBottomColor:
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
399 case CSSPropertyWidth: 558 case CSSPropertyWidth:
400 case CSSPropertyWordSpacing: 559 case CSSPropertyWordSpacing:
401 case CSSPropertyZIndex: 560 case CSSPropertyZIndex:
402 case CSSPropertyZoom: 561 case CSSPropertyZoom:
403 return true; 562 return true;
404 default: 563 default:
405 return false; 564 return false;
406 } 565 }
407 } 566 }
408 567
568 const StylePropertyShorthand& CSSAnimations::animatableProperties()
569 {
570 DEFINE_STATIC_LOCAL(Vector<CSSPropertyID>, properties, ());
571 DEFINE_STATIC_LOCAL(StylePropertyShorthand, propertyShorthand, ());
572 if (properties.isEmpty()) {
573 for (int i = firstCSSProperty; i < lastCSSProperty; ++i) {
574 CSSPropertyID id = convertToCSSPropertyID(i);
575 // FIXME: This is the only shorthand marked as animatable,
576 // it'll be removed from the list once we switch to the new implemen tation.
577 if (id == CSSPropertyFlex)
578 continue;
579 if (isAnimatableProperty(id))
580 properties.append(id);
581 }
582 propertyShorthand = StylePropertyShorthand(CSSPropertyInvalid, propertie s.begin(), properties.size());
583 }
584 return propertyShorthand;
585 }
586
409 } // namespace WebCore 587 } // 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