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 | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |