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/EventNames.h" | 42 #include "core/events/EventNames.h" |
| 43 #include "core/events/TransitionEvent.h" | |
| 41 #include "core/events/WebKitAnimationEvent.h" | 44 #include "core/events/WebKitAnimationEvent.h" |
| 45 // FIXME: Remove this once all properties are supported | |
| 46 #include "core/page/animation/CSSPropertyAnimation.h" | |
| 42 #include "core/platform/animation/CSSAnimationDataList.h" | 47 #include "core/platform/animation/CSSAnimationDataList.h" |
| 43 #include "core/platform/animation/TimingFunction.h" | 48 #include "core/platform/animation/TimingFunction.h" |
| 44 #include "wtf/HashSet.h" | 49 #include "wtf/HashSet.h" |
| 45 | 50 |
| 46 namespace { | 51 namespace { |
| 47 | 52 |
| 48 using namespace WebCore; | 53 using namespace WebCore; |
| 49 | 54 |
| 50 bool isEarlierPhase(TimedItem::Phase target, TimedItem::Phase reference) | 55 bool isEarlierPhase(TimedItem::Phase target, TimedItem::Phase reference) |
| 51 { | 56 { |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 136 CSSAnimationUpdateScope::~CSSAnimationUpdateScope() | 141 CSSAnimationUpdateScope::~CSSAnimationUpdateScope() |
| 137 { | 142 { |
| 138 if (!m_target) | 143 if (!m_target) |
| 139 return; | 144 return; |
| 140 ActiveAnimations* activeAnimations = m_target->activeAnimations(); | 145 ActiveAnimations* activeAnimations = m_target->activeAnimations(); |
| 141 CSSAnimations* cssAnimations = activeAnimations ? activeAnimations->cssAnima tions() : 0; | 146 CSSAnimations* cssAnimations = activeAnimations ? activeAnimations->cssAnima tions() : 0; |
| 142 if (cssAnimations) | 147 if (cssAnimations) |
| 143 cssAnimations->maybeApplyPendingUpdate(m_target); | 148 cssAnimations->maybeApplyPendingUpdate(m_target); |
| 144 } | 149 } |
| 145 | 150 |
| 146 bool CSSAnimations::needsUpdate(const Element* element, const RenderStyle* style ) | 151 PassOwnPtr<CSSAnimationUpdate> CSSAnimations::calculateUpdate(Element* element, const RenderStyle* style, StyleResolver* resolver) |
| 152 { | |
| 153 ASSERT(RuntimeEnabledFeatures::webAnimationsCSSEnabled()); | |
| 154 OwnPtr<CSSAnimationUpdate> update = adoptPtr(new CSSAnimationUpdate()); | |
| 155 updateAnimationUpdate(update.get(), element, style, resolver); | |
|
dstockwell
2013/10/08 21:02:59
I think calculateAnimationUpdate and calculateTran
Timothy Loh
2013/10/09 01:33:07
Done.
| |
| 156 updateTransitionUpdate(update.get(), element, style); | |
| 157 return update->isEmpty() ? nullptr : update.release(); | |
| 158 } | |
| 159 | |
| 160 void CSSAnimations::updateAnimationUpdate(CSSAnimationUpdate* update, Element* e lement, const RenderStyle* style, StyleResolver* resolver) | |
| 147 { | 161 { |
| 148 ActiveAnimations* activeAnimations = element->activeAnimations(); | 162 ActiveAnimations* activeAnimations = element->activeAnimations(); |
| 149 const CSSAnimationDataList* animations = style->animations(); | 163 const CSSAnimationDataList* animationDataList = style->animations(); |
| 150 const CSSAnimations* cssAnimations = activeAnimations ? activeAnimations->cs sAnimations() : 0; | 164 const CSSAnimations* cssAnimations = activeAnimations ? activeAnimations->cs sAnimations() : 0; |
| 151 EDisplay display = style->display(); | |
| 152 return (display != NONE && animations && animations->size()) || (cssAnimatio ns && !cssAnimations->isEmpty()); | |
|
dstockwell
2013/10/08 21:02:59
where did this display != NONE check go?
Timothy Loh
2013/10/09 01:33:07
Looks redundant - if display is none and cssAnimat
| |
| 153 } | |
| 154 | 165 |
| 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; | 166 HashSet<AtomicString> inactive; |
| 159 if (cssAnimations) | 167 if (cssAnimations) |
| 160 for (AnimationMap::const_iterator iter = cssAnimations->m_animations.beg in(); iter != cssAnimations->m_animations.end(); ++iter) | 168 for (AnimationMap::const_iterator iter = cssAnimations->m_animations.beg in(); iter != cssAnimations->m_animations.end(); ++iter) |
| 161 inactive.add(iter->key); | 169 inactive.add(iter->key); |
| 162 | 170 |
| 163 if (style->display() != NONE) { | 171 if (style->display() != NONE) { |
| 164 for (size_t i = 0; animationDataList && i < animationDataList->size(); + +i) { | 172 for (size_t i = 0; animationDataList && i < animationDataList->size(); + +i) { |
| 165 const CSSAnimationData* animationData = animationDataList->animation (i); | 173 const CSSAnimationData* animationData = animationDataList->animation (i); |
| 166 if (animationData->isNoneAnimation()) | 174 if (animationData->isNoneAnimation()) |
| 167 continue; | 175 continue; |
| 168 ASSERT(animationData->isValidAnimation()); | 176 ASSERT(animationData->isValidAnimation()); |
| 169 AtomicString animationName(animationData->name()); | 177 AtomicString animationName(animationData->name()); |
| 170 | 178 |
| 171 if (cssAnimations) { | 179 if (cssAnimations) { |
| 172 AnimationMap::const_iterator existing(cssAnimations->m_animation s.find(animationName)); | 180 AnimationMap::const_iterator existing(cssAnimations->m_animation s.find(animationName)); |
| 173 if (existing != cssAnimations->m_animations.end()) { | 181 if (existing != cssAnimations->m_animations.end()) { |
| 174 // FIXME: The play-state of this animation might have change d, record the change in the update. | 182 // FIXME: The play-state of this animation might have change d, record the change in the update. |
| 175 inactive.remove(animationName); | 183 inactive.remove(animationName); |
| 176 continue; | 184 continue; |
| 177 } | 185 } |
| 178 } | 186 } |
| 179 | 187 |
| 180 Timing timing; | 188 Timing timing; |
| 181 RefPtr<TimingFunction> defaultTimingFunction = timingFromAnimationDa ta(animationData, timing); | 189 RefPtr<TimingFunction> defaultTimingFunction = timingFromAnimationDa ta(animationData, timing); |
| 182 Vector<std::pair<KeyframeAnimationEffect::KeyframeVector, RefPtr<Tim ingFunction> > > keyframesAndTimingFunctions; | 190 Vector<std::pair<KeyframeAnimationEffect::KeyframeVector, RefPtr<Tim ingFunction> > > keyframesAndTimingFunctions; |
| 183 resolver->resolveKeyframes(element, style, animationName, defaultTim ingFunction.get(), keyframesAndTimingFunctions); | 191 resolver->resolveKeyframes(element, style, animationName, defaultTim ingFunction.get(), keyframesAndTimingFunctions); |
| 184 if (!keyframesAndTimingFunctions.isEmpty()) { | 192 if (!keyframesAndTimingFunctions.isEmpty()) { |
| 185 if (!update) | |
| 186 update = adoptPtr(new CSSAnimationUpdate()); | |
| 187 HashSet<RefPtr<InertAnimation> > animations; | 193 HashSet<RefPtr<InertAnimation> > animations; |
| 188 for (size_t j = 0; j < keyframesAndTimingFunctions.size(); ++j) { | 194 for (size_t j = 0; j < keyframesAndTimingFunctions.size(); ++j) { |
| 189 ASSERT(!keyframesAndTimingFunctions[j].first.isEmpty()); | 195 ASSERT(!keyframesAndTimingFunctions[j].first.isEmpty()); |
| 190 timing.timingFunction = keyframesAndTimingFunctions[j].secon d; | 196 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. | 197 // 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)); | 198 animations.add(InertAnimation::create(KeyframeAnimationEffec t::create(keyframesAndTimingFunctions[j].first), timing)); |
| 193 } | 199 } |
| 194 update->startAnimation(animationName, animations); | 200 update->startAnimation(animationName, animations); |
| 195 } | 201 } |
| 196 } | 202 } |
| 197 } | 203 } |
| 198 | 204 |
| 199 if (!inactive.isEmpty() && !update) | |
| 200 update = adoptPtr(new CSSAnimationUpdate()); | |
| 201 for (HashSet<AtomicString>::const_iterator iter = inactive.begin(); iter != inactive.end(); ++iter) | 205 for (HashSet<AtomicString>::const_iterator iter = inactive.begin(); iter != inactive.end(); ++iter) |
| 202 update->cancelAnimation(*iter, cssAnimations->m_animations.get(*iter)); | 206 update->cancelAnimation(*iter, cssAnimations->m_animations.get(*iter)); |
| 203 | |
| 204 return update.release(); | |
| 205 } | 207 } |
| 206 | 208 |
| 207 void CSSAnimations::maybeApplyPendingUpdate(Element* element) | 209 void CSSAnimations::maybeApplyPendingUpdate(Element* element) |
| 208 { | 210 { |
| 209 if (!element->renderer()) | 211 if (!element->renderer()) |
| 210 m_pendingUpdate = nullptr; | 212 m_pendingUpdate = nullptr; |
| 211 | 213 |
| 212 if (!m_pendingUpdate) | 214 if (!m_pendingUpdate) |
| 213 return; | 215 return; |
| 214 | 216 |
| 215 OwnPtr<CSSAnimationUpdate> update = m_pendingUpdate.release(); | 217 OwnPtr<CSSAnimationUpdate> update = m_pendingUpdate.release(); |
| 216 | 218 |
| 217 for (Vector<AtomicString>::const_iterator iter = update->cancelledAnimationN ames().begin(); iter != update->cancelledAnimationNames().end(); ++iter) { | 219 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); | 220 const HashSet<RefPtr<Player> >& players = m_animations.take(*iter); |
| 219 for (HashSet<RefPtr<Player> >::const_iterator iter = players.begin(); it er != players.end(); ++iter) | 221 for (HashSet<RefPtr<Player> >::const_iterator iter = players.begin(); it er != players.end(); ++iter) |
| 220 (*iter)->cancel(); | 222 (*iter)->cancel(); |
| 221 } | 223 } |
| 222 | 224 |
| 223 // FIXME: Apply updates to play-state. | 225 // FIXME: Apply updates to play-state. |
| 224 | 226 |
| 225 for (Vector<CSSAnimationUpdate::NewAnimation>::const_iterator iter = update- >newAnimations().begin(); iter != update->newAnimations().end(); ++iter) { | 227 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)); | 228 OwnPtr<AnimationEventDelegate> eventDelegate = adoptPtr(new AnimationEve ntDelegate(element, iter->name)); |
| 227 HashSet<RefPtr<Player> > players; | 229 HashSet<RefPtr<Player> > players; |
| 228 for (HashSet<RefPtr<InertAnimation> >::const_iterator animationsIter = i ter->animations.begin(); animationsIter != iter->animations.end(); ++animationsI ter) { | 230 for (HashSet<RefPtr<InertAnimation> >::const_iterator animationsIter = i ter->animations.begin(); animationsIter != iter->animations.end(); ++animationsI ter) { |
| 229 const InertAnimation* inertAnimation = animationsIter->get(); | 231 const InertAnimation* inertAnimation = animationsIter->get(); |
| 230 // The event delegate is set on the the first animation only. We | 232 // The event delegate is set on the the first animation only. We |
| 231 // rely on the behavior of OwnPtr::release() to achieve this. | 233 // rely on the behavior of OwnPtr::release() to achieve this. |
| 232 RefPtr<Animation> animation = Animation::create(element, inertAnimat ion->effect(), inertAnimation->specified(), eventDelegate.release()); | 234 RefPtr<Animation> animation = Animation::create(element, inertAnimat ion->effect(), inertAnimation->specified(), eventDelegate.release()); |
| 233 players.add(element->document().timeline()->play(animation.get())); | 235 players.add(element->document().timeline()->play(animation.get())); |
| 234 } | 236 } |
| 235 m_animations.set(iter->name, players); | 237 m_animations.set(iter->name, players); |
| 236 } | 238 } |
| 239 | |
| 240 Vector<CSSPropertyID> removedTransitions; | |
| 241 for (TransitionMap::iterator iter = m_transitions.begin(); iter != m_transit ions.end(); ++iter) { | |
|
dstockwell
2013/10/08 21:02:59
Why are we iterating over the transition map rathe
Timothy Loh
2013/10/09 01:33:07
Because I'm silly :(
| |
| 242 Player* player = iter->value.get(); | |
| 243 CSSPropertyID id = iter->key; | |
| 244 if (update->endedTransitions().contains(id)) { | |
| 245 player->cancel(); | |
| 246 removedTransitions.append(id); | |
| 247 } | |
| 248 } | |
| 249 for (int i = 0; i < removedTransitions.size(); ++i) | |
|
dstockwell
2013/10/08 21:02:59
Should this be size_t?
Timothy Loh
2013/10/09 01:33:07
Loop removed (changed to loop over cancelled trans
| |
| 250 m_transitions.remove(removedTransitions[i]); | |
|
Steve Block
2013/10/09 00:57:12
Why do you use two passes to remove the cancelled
Timothy Loh
2013/10/09 01:33:07
Doug had the same comment. Fixed.
| |
| 251 | |
| 252 HashMap<CSSPropertyID, RefPtr<InertAnimation> >::const_iterator iter; | |
| 253 for (iter = update->newTransitions().begin(); iter != update->newTransitions ().end(); ++iter) { | |
| 254 CSSPropertyID id = iter->key; | |
| 255 OwnPtr<TransitionEventDelegate> eventDelegate = adoptPtr(new TransitionE ventDelegate(element, id)); | |
| 256 RefPtr<Animation> transition = Animation::create(element, iter->value->e ffect(), iter->value->specified(), eventDelegate.release()); | |
| 257 // FIXME: We'll probably want a separate DocumentTimeline for transition s, or | |
| 258 // at least to not have transitions also added to the default AnimationS tack. | |
| 259 Player* player = element->document().timeline()->play(transition.get()). get(); | |
| 260 m_transitions.set(id, player); | |
| 261 } | |
| 262 } | |
| 263 | |
| 264 namespace { | |
|
Steve Block
2013/10/09 00:57:12
You should merge this with the anonymous namespace
Timothy Loh
2013/10/09 07:39:23
Done. Also moved the existing function timingFromA
| |
| 265 | |
| 266 struct TransitionDetails { | |
| 267 TransitionDetails(PassRefPtr<AnimatableValue> from, PassRefPtr<AnimatableVal ue> to, const CSSAnimationData* anim) | |
| 268 : from(from), to(to), anim(anim) | |
|
dstockwell
2013/10/08 21:02:59
place to and anim on separate lines for consistenc
Timothy Loh
2013/10/09 01:33:07
Done.
| |
| 269 { | |
| 270 } | |
| 271 TransitionDetails() { } // The HashMap calls the default ctor | |
| 272 RefPtr<AnimatableValue> from; | |
| 273 RefPtr<AnimatableValue> to; | |
| 274 const CSSAnimationData* anim; | |
| 275 }; | |
| 276 typedef HashMap<CSSPropertyID, TransitionDetails> StyleChange; | |
| 277 | |
| 278 void updateIfPropertyChanged(const CSSAnimationData* anim, CSSPropertyID id, con st RenderStyle* oldStyle, const RenderStyle* newStyle, StyleChange& styleChange) | |
| 279 { | |
| 280 RefPtr<AnimatableValue> from = CSSAnimatableValueFactory::create(id, oldStyl e); | |
|
dstockwell
2013/10/08 21:02:59
If there's already a transition running on this pr
| |
| 281 RefPtr<AnimatableValue> to = CSSAnimatableValueFactory::create(id, newStyle) ; | |
| 282 // If we have multiple transitions on the same property, we will use the | |
| 283 // last one since we iterate over them in order and this will override | |
| 284 // a previously set TransitionDetails. | |
| 285 if (!from->equals(to.get())) | |
| 286 styleChange.add(id, TransitionDetails(from, to, anim)); | |
| 287 } | |
| 288 | |
| 289 void computeStyleChange(const RenderStyle* oldStyle, const RenderStyle* newStyle , StyleChange& styleChange, HashSet<CSSPropertyID>& listedProperties) | |
| 290 { | |
| 291 if (!newStyle->transitions()) | |
| 292 return; | |
| 293 | |
| 294 for (size_t i = 0; i < newStyle->transitions()->size(); ++i) { | |
| 295 const CSSAnimationData* anim = newStyle->transitions()->animation(i); | |
| 296 CSSAnimationData::AnimationMode mode = anim->animationMode(); | |
| 297 if (anim->duration() + anim->delay() <= 0 || mode == CSSAnimationData::A nimateNone) | |
| 298 continue; | |
| 299 | |
| 300 if (mode == CSSAnimationData::AnimateAll) { | |
| 301 const Vector<CSSPropertyID>& animatableProperties = CSSAnimations::a nimatableProperties(); | |
| 302 for (unsigned i = 0; i < animatableProperties.size(); ++i) { | |
| 303 CSSPropertyID id = animatableProperties[i]; | |
| 304 listedProperties.add(id); | |
| 305 // FIXME: We haven't yet added support for all animatable proper ties, | |
| 306 // so this check lets us transition 'all' without failing to pul l | |
| 307 // values out of the RenderStyles. | |
| 308 if (CSSPropertyAnimation::propertiesEqual(id, oldStyle, newStyle )) | |
|
dstockwell
2013/10/08 21:02:59
Could we just skip over the specific properties th
Steve Block
2013/10/09 00:57:12
I don't see how testing for equality means we skip
Timothy Loh
2013/10/09 01:33:07
Not sure what you mean here. The check is just so
Timothy Loh
2013/10/09 07:39:23
OK. Will take this out for now. This takes it from
| |
| 309 continue; | |
| 310 updateIfPropertyChanged(anim, id, oldStyle, newStyle, styleChang e); | |
| 311 } | |
| 312 continue; | |
| 313 } | |
| 314 | |
|
dstockwell
2013/10/08 21:02:59
ASSERT mode == AnimateSingleProperty
Timothy Loh
2013/10/09 01:33:07
Done.
| |
| 315 const StylePropertyShorthand& propertyList = shorthandForProperty(anim-> property()); | |
| 316 if (!propertyList.length()) { | |
| 317 listedProperties.add(anim->property()); | |
| 318 updateIfPropertyChanged(anim, anim->property(), oldStyle, newStyle, styleChange); | |
| 319 } else { | |
| 320 for (unsigned i = 0; i < propertyList.length(); ++i) { | |
| 321 CSSPropertyID id = propertyList.properties()[i]; | |
| 322 if (!CSSAnimations::isAnimatableProperty(id)) | |
| 323 continue; | |
| 324 listedProperties.add(id); | |
| 325 updateIfPropertyChanged(anim, id, oldStyle, newStyle, styleChang e); | |
|
Steve Block
2013/10/09 00:57:12
Can you merge this block with the AnimateAll case
Timothy Loh
2013/10/09 07:39:23
OK, I changed animatableProperties to return a con
| |
| 326 } | |
| 327 } | |
| 328 } | |
| 329 } | |
| 330 | |
| 331 } // namespace | |
| 332 | |
| 333 void CSSAnimations::updateTransitionUpdate(CSSAnimationUpdate* update, CSSProper tyID id, const AnimatableValue* from, const AnimatableValue* to, const CSSAnimat ionData* anim, const TransitionMap* transitions) | |
|
dstockwell
2013/10/08 21:02:59
calculateTransitionUpdateForProperty
Timothy Loh
2013/10/09 01:33:07
Done.
| |
| 334 { | |
| 335 // FIXME: Skip the rest of this if there is a running animation on this prop erty | |
| 336 | |
| 337 Timing timing; | |
| 338 RefPtr<TimingFunction> timingFunction = timingFromAnimationData(anim, timing ); | |
| 339 timing.timingFunction = timingFunction; | |
| 340 timing.fillMode = Timing::FillModeBoth; | |
| 341 | |
| 342 if (transitions) { | |
| 343 TransitionMap::const_iterator existingTransitionIter = transitions->find (id); | |
| 344 | |
| 345 if (existingTransitionIter != transitions->end() && !update->endedTransi tions().contains(id)) { | |
| 346 const Animation* animation = static_cast<const Animation*>(existingT ransitionIter->value->source()); | |
|
dstockwell
2013/10/08 21:02:59
I don't like reaching in here to pull out the targ
Steve Block
2013/10/09 00:57:12
Agreed
Timothy Loh
2013/10/09 07:39:23
OK. Plumbing these explicitly through now. Also ch
| |
| 347 const KeyframeAnimationEffect* existingEffect = static_cast<const Ke yframeAnimationEffect*>(animation->effect()); | |
| 348 | |
| 349 ASSERT(existingEffect->getFrames().size() == 2); | |
| 350 const AnimatableValue* existingTo = existingEffect->getFrames()[1]-> propertyValue(id); | |
| 351 | |
| 352 if (existingTo->equals(to)) | |
| 353 return; | |
| 354 update->endTransition(id); | |
| 355 } | |
| 356 } | |
| 357 | |
| 358 KeyframeAnimationEffect::KeyframeVector keyframes; | |
| 359 | |
| 360 RefPtr<Keyframe> startKeyframe = Keyframe::create(); | |
| 361 startKeyframe->setPropertyValue(id, from); | |
| 362 startKeyframe->setOffset(0); | |
| 363 keyframes.append(startKeyframe); | |
| 364 | |
| 365 RefPtr<Keyframe> endKeyframe = Keyframe::create(); | |
| 366 endKeyframe->setPropertyValue(id, to); | |
| 367 endKeyframe->setOffset(1); | |
| 368 keyframes.append(endKeyframe); | |
| 369 | |
| 370 RefPtr<KeyframeAnimationEffect> effect = KeyframeAnimationEffect::create(key frames); | |
| 371 | |
| 372 update->startTransition(id, InertAnimation::create(effect, timing)); | |
| 373 } | |
| 374 | |
| 375 void CSSAnimations::updateTransitionUpdate(CSSAnimationUpdate* update, const Ele ment* element, const RenderStyle* style) | |
| 376 { | |
| 377 ActiveAnimations* activeAnimations = element->activeAnimations(); | |
| 378 const CSSAnimations* cssAnimations = activeAnimations ? activeAnimations->cs sAnimations() : 0; | |
| 379 const TransitionMap* transitions = cssAnimations ? &cssAnimations->m_transit ions : 0; | |
| 380 | |
| 381 HashSet<CSSPropertyID> listedProperties; | |
| 382 if (style->display() != NONE && element->renderer() && element->renderer()-> style()) { | |
|
dstockwell
2013/10/08 21:02:59
if display is none, there's should be nothing to d
Timothy Loh
2013/10/09 01:33:07
For animations, it looks like we'll set all the ru
| |
| 383 StyleChange styleChange; | |
| 384 computeStyleChange(element->renderer()->style(), style, styleChange, lis tedProperties); | |
| 385 for (StyleChange::const_iterator iter = styleChange.begin(); iter != sty leChange.end(); ++iter) { | |
| 386 CSSPropertyID id = iter->key; | |
| 387 AnimatableValue* from = iter->value.from.get(); | |
| 388 AnimatableValue* to = iter->value.to.get(); | |
| 389 const CSSAnimationData* anim = iter->value.anim; | |
| 390 updateTransitionUpdate(update, id, from, to, anim, transitions); | |
| 391 } | |
| 392 } | |
| 393 | |
| 394 if (transitions) { | |
| 395 for (TransitionMap::const_iterator iter = transitions->begin(); iter != transitions->end(); ++iter) { | |
| 396 const TimedItem* timedItem = iter->value->source(); | |
| 397 bool isReversed = timedItem->specified().playbackRate < 0; | |
|
dstockwell
2013/10/08 21:02:59
Reversing doesn't seem to be implemented, can we r
Timothy Loh
2013/10/09 01:33:07
Whoops, I pulled most of it out for a separate pat
| |
| 398 TimedItem::Phase end = isReversed ? TimedItem::PhaseBefore : TimedIt em::PhaseAfter; | |
| 399 if (timedItem->phase() == end || !listedProperties.contains(iter->ke y)) | |
| 400 update->endTransition(iter->key); | |
| 401 } | |
| 402 } | |
| 403 } | |
| 404 | |
| 405 | |
| 406 AnimationEffect::CompositableValueMap CSSAnimations::compositableValuesForTransi tions(const CSSAnimations* cssAnimations, const CSSAnimationUpdate* update) | |
|
dstockwell
2013/10/08 21:02:59
If the transitions are being added to the document
Timothy Loh
2013/10/09 07:39:23
This mean that frame 0 will show the end state, si
| |
| 407 { | |
| 408 // FIXME: Transitions shouldn't apply values for properties with a running C SS Animation. | |
| 409 AnimationEffect::CompositableValueMap result; | |
| 410 | |
| 411 if (cssAnimations) { | |
| 412 const TransitionMap& transitions = cssAnimations->m_transitions; | |
| 413 for (TransitionMap::const_iterator iter = transitions.begin(); iter != t ransitions.end(); ++iter) { | |
| 414 CSSPropertyID id = iter->key; | |
| 415 if (update && update->endedTransitions().contains(id)) | |
| 416 continue; | |
| 417 Player* player = iter->value.get(); | |
| 418 Animation* animation = static_cast<Animation*>(player->source()); | |
| 419 ASSERT(animation && animation->compositableValues()); | |
| 420 const AnimationEffect::CompositableValueMap* compositableValues = an imation->compositableValues(); | |
| 421 ASSERT(compositableValues->size() == 1 && compositableValues->contai ns(id)); | |
| 422 result.set(id, compositableValues->get(id)); | |
| 423 } | |
| 424 } | |
| 425 | |
| 426 if (update) { | |
| 427 HashMap<CSSPropertyID, RefPtr<InertAnimation> >::const_iterator iter; | |
|
dstockwell
2013/10/08 21:02:59
Put this on the next line
Timothy Loh
2013/10/09 01:33:07
Makes the line a bit long but OK.
| |
| 428 for (iter = update->newTransitions().begin(); iter != update->newTransit ions().end(); ++iter) { | |
| 429 CSSPropertyID id = iter->key; | |
| 430 InertAnimation* animation = iter->value.get(); | |
| 431 OwnPtr<AnimationEffect::CompositableValueMap> compositableValues = a nimation->sample(); | |
| 432 ASSERT(compositableValues->size() == 1 && compositableValues->contai ns(id)); | |
| 433 result.set(id, compositableValues->get(id)); | |
| 434 } | |
| 435 } | |
| 436 | |
| 437 return result; | |
| 237 } | 438 } |
| 238 | 439 |
| 239 void CSSAnimations::cancel() | 440 void CSSAnimations::cancel() |
| 240 { | 441 { |
| 241 for (AnimationMap::iterator iter = m_animations.begin(); iter != m_animation s.end(); ++iter) { | 442 for (AnimationMap::iterator iter = m_animations.begin(); iter != m_animation s.end(); ++iter) { |
| 242 const HashSet<RefPtr<Player> >& players = iter->value; | 443 const HashSet<RefPtr<Player> >& players = iter->value; |
| 243 for (HashSet<RefPtr<Player> >::const_iterator animationsIter = players.b egin(); animationsIter != players.end(); ++animationsIter) | 444 for (HashSet<RefPtr<Player> >::const_iterator animationsIter = players.b egin(); animationsIter != players.end(); ++animationsIter) |
| 244 (*animationsIter)->cancel(); | 445 (*animationsIter)->cancel(); |
| 245 } | 446 } |
| 246 | 447 |
| 448 for (TransitionMap::iterator iter = m_transitions.begin(); iter != m_transit ions.end(); ++iter) | |
| 449 iter->value->cancel(); | |
| 450 | |
| 247 m_animations.clear(); | 451 m_animations.clear(); |
|
dstockwell
2013/10/08 21:02:59
m_transitions.clear()
Timothy Loh
2013/10/09 01:33:07
Done.
| |
| 248 m_pendingUpdate = nullptr; | 452 m_pendingUpdate = nullptr; |
| 249 } | 453 } |
| 250 | 454 |
| 251 void CSSAnimations::EventDelegate::maybeDispatch(Document::ListenerType listener Type, AtomicString& eventName, double elapsedTime) | 455 void CSSAnimations::AnimationEventDelegate::maybeDispatch(Document::ListenerType listenerType, AtomicString& eventName, double elapsedTime) |
| 252 { | 456 { |
| 253 if (m_target->document().hasListenerType(listenerType)) | 457 if (m_target->document().hasListenerType(listenerType)) |
| 254 m_target->document().timeline()->addEventToDispatch(m_target, WebKitAnim ationEvent::create(eventName, m_name, elapsedTime)); | 458 m_target->document().timeline()->addEventToDispatch(m_target, WebKitAnim ationEvent::create(eventName, m_name, elapsedTime)); |
| 255 } | 459 } |
| 256 | 460 |
| 257 void CSSAnimations::EventDelegate::onEventCondition(const TimedItem* timedItem, bool isFirstSample, TimedItem::Phase previousPhase, double previousIteration) | 461 void CSSAnimations::AnimationEventDelegate::onEventCondition(const TimedItem* ti medItem, bool isFirstSample, TimedItem::Phase previousPhase, double previousIter ation) |
| 258 { | 462 { |
| 259 // Events for a single document are queued and dispatched as a group at | 463 // Events for a single document are queued and dispatched as a group at |
| 260 // the end of DocumentTimeline::serviceAnimations. | 464 // the end of DocumentTimeline::serviceAnimations. |
| 261 // FIXME: Events which are queued outside of serviceAnimations should | 465 // FIXME: Events which are queued outside of serviceAnimations should |
| 262 // trigger a timer to dispatch when control is released. | 466 // trigger a timer to dispatch when control is released. |
| 263 const TimedItem::Phase currentPhase = timedItem->phase(); | 467 const TimedItem::Phase currentPhase = timedItem->phase(); |
| 264 const double currentIteration = timedItem->currentIteration(); | 468 const double currentIteration = timedItem->currentIteration(); |
| 265 | 469 |
| 266 // Note that the elapsedTime is measured from when the animation starts play ing. | 470 // 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) { | 471 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); | 484 ASSERT(timedItem->specified().startDelay > 0 || isFirstSample); |
| 281 // The spec states that the elapsed time should be | 485 // The spec states that the elapsed time should be |
| 282 // 'delay < 0 ? -delay : 0', but we always use 0 to match the existing | 486 // 'delay < 0 ? -delay : 0', but we always use 0 to match the existing |
| 283 // implementation. See crbug.com/279611 | 487 // implementation. See crbug.com/279611 |
| 284 maybeDispatch(Document::ANIMATIONSTART_LISTENER, eventNames().animations tartEvent, 0); | 488 maybeDispatch(Document::ANIMATIONSTART_LISTENER, eventNames().animations tartEvent, 0); |
| 285 } | 489 } |
| 286 if ((isFirstSample || isEarlierPhase(previousPhase, TimedItem::PhaseAfter)) && currentPhase == TimedItem::PhaseAfter) | 490 if ((isFirstSample || isEarlierPhase(previousPhase, TimedItem::PhaseAfter)) && currentPhase == TimedItem::PhaseAfter) |
| 287 maybeDispatch(Document::ANIMATIONEND_LISTENER, eventNames().animationend Event, timedItem->activeDuration()); | 491 maybeDispatch(Document::ANIMATIONEND_LISTENER, eventNames().animationend Event, timedItem->activeDuration()); |
| 288 } | 492 } |
| 289 | 493 |
| 494 void CSSAnimations::TransitionEventDelegate::onEventCondition(const TimedItem* t imedItem, bool isFirstSample, TimedItem::Phase previousPhase, double previousIte ration) | |
| 495 { | |
| 496 // Events for a single document are queued and dispatched as a group at | |
| 497 // the end of DocumentTimeline::serviceAnimations. | |
| 498 // FIXME: Events which are queued outside of serviceAnimations should | |
| 499 // trigger a timer to dispatch when control is released. | |
| 500 const TimedItem::Phase currentPhase = timedItem->phase(); | |
| 501 if (currentPhase == TimedItem::PhaseActive || previousPhase == currentPhase) | |
|
dstockwell
2013/10/08 21:02:59
Shouldn't we only be firing when currentPhase beco
Timothy Loh
2013/10/09 01:33:07
Tweaked condition slightly.
| |
| 502 return; | |
| 503 if (m_target->document().hasListenerType(Document::TRANSITIONEND_LISTENER)) { | |
| 504 String propertyName = getPropertyNameString(m_id); | |
| 505 const Timing& timing = timedItem->specified(); | |
| 506 double elapsedTime = timing.iterationDuration; | |
| 507 const AtomicString& eventType = eventNames().transitionendEvent; | |
| 508 String pseudoElement = PseudoElement::pseudoElementNameForEvents(m_targe t->pseudoId()); | |
| 509 m_target->document().timeline()->addEventToDispatch(m_target, Transition Event::create(eventType, propertyName, elapsedTime, pseudoElement)); | |
| 510 } | |
| 511 } | |
| 512 | |
| 513 | |
| 290 bool CSSAnimations::isAnimatableProperty(CSSPropertyID property) | 514 bool CSSAnimations::isAnimatableProperty(CSSPropertyID property) |
| 291 { | 515 { |
| 292 switch (property) { | 516 switch (property) { |
| 293 case CSSPropertyBackgroundColor: | 517 case CSSPropertyBackgroundColor: |
| 294 case CSSPropertyBackgroundImage: | 518 case CSSPropertyBackgroundImage: |
| 295 case CSSPropertyBackgroundPositionX: | 519 case CSSPropertyBackgroundPositionX: |
| 296 case CSSPropertyBackgroundPositionY: | 520 case CSSPropertyBackgroundPositionY: |
| 297 case CSSPropertyBackgroundSize: | 521 case CSSPropertyBackgroundSize: |
| 298 case CSSPropertyBaselineShift: | 522 case CSSPropertyBaselineShift: |
| 299 case CSSPropertyBorderBottomColor: | 523 case CSSPropertyBorderBottomColor: |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 391 case CSSPropertyWidth: | 615 case CSSPropertyWidth: |
| 392 case CSSPropertyWordSpacing: | 616 case CSSPropertyWordSpacing: |
| 393 case CSSPropertyZIndex: | 617 case CSSPropertyZIndex: |
| 394 case CSSPropertyZoom: | 618 case CSSPropertyZoom: |
| 395 return true; | 619 return true; |
| 396 default: | 620 default: |
| 397 return false; | 621 return false; |
| 398 } | 622 } |
| 399 } | 623 } |
| 400 | 624 |
| 625 const Vector<CSSPropertyID>& CSSAnimations::animatableProperties() | |
| 626 { | |
| 627 DEFINE_STATIC_LOCAL(Vector<CSSPropertyID>, properties, ()); | |
| 628 if (properties.isEmpty()) { | |
| 629 for (int i = firstCSSProperty; i < lastCSSProperty; ++i) { | |
| 630 CSSPropertyID id = convertToCSSPropertyID(i); | |
| 631 if (isAnimatableProperty(id)) | |
| 632 properties.append(id); | |
| 633 } | |
| 634 } | |
| 635 return properties; | |
| 636 } | |
| 637 | |
| 401 } // namespace WebCore | 638 } // namespace WebCore |
| OLD | NEW |