Chromium Code Reviews| 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 13 matching lines...) Expand all Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |