| 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 24 matching lines...) Expand all Loading... |
| 35 #include "sky/engine/core/animation/ActiveAnimations.h" | 35 #include "sky/engine/core/animation/ActiveAnimations.h" |
| 36 #include "sky/engine/core/animation/AnimationTimeline.h" | 36 #include "sky/engine/core/animation/AnimationTimeline.h" |
| 37 #include "sky/engine/core/animation/KeyframeEffectModel.h" | 37 #include "sky/engine/core/animation/KeyframeEffectModel.h" |
| 38 #include "sky/engine/core/animation/LegacyStyleInterpolation.h" | 38 #include "sky/engine/core/animation/LegacyStyleInterpolation.h" |
| 39 #include "sky/engine/core/animation/css/CSSAnimatableValueFactory.h" | 39 #include "sky/engine/core/animation/css/CSSAnimatableValueFactory.h" |
| 40 #include "sky/engine/core/animation/css/CSSPropertyEquality.h" | 40 #include "sky/engine/core/animation/css/CSSPropertyEquality.h" |
| 41 #include "sky/engine/core/css/CSSPropertyMetadata.h" | 41 #include "sky/engine/core/css/CSSPropertyMetadata.h" |
| 42 #include "sky/engine/core/css/CSSValueList.h" | 42 #include "sky/engine/core/css/CSSValueList.h" |
| 43 #include "sky/engine/core/css/StyleKeyframe.h" | 43 #include "sky/engine/core/css/StyleKeyframe.h" |
| 44 #include "sky/engine/core/css/StyleRuleKeyframes.h" | 44 #include "sky/engine/core/css/StyleRuleKeyframes.h" |
| 45 #include "sky/engine/core/css/resolver/CSSToStyleMap.h" | |
| 46 #include "sky/engine/core/css/resolver/StyleResolver.h" | |
| 47 #include "sky/engine/core/dom/Element.h" | 45 #include "sky/engine/core/dom/Element.h" |
| 48 #include "sky/engine/core/dom/StyleEngine.h" | |
| 49 #include "sky/engine/core/events/AnimationEvent.h" | 46 #include "sky/engine/core/events/AnimationEvent.h" |
| 50 #include "sky/engine/core/events/TransitionEvent.h" | 47 #include "sky/engine/core/events/TransitionEvent.h" |
| 51 #include "sky/engine/core/rendering/RenderLayer.h" | 48 #include "sky/engine/core/rendering/RenderLayer.h" |
| 52 #include "sky/engine/core/rendering/RenderObject.h" | 49 #include "sky/engine/core/rendering/RenderObject.h" |
| 53 #include "sky/engine/core/rendering/style/KeyframeList.h" | 50 #include "sky/engine/core/rendering/style/KeyframeList.h" |
| 54 #include "sky/engine/platform/animation/TimingFunction.h" | 51 #include "sky/engine/platform/animation/TimingFunction.h" |
| 55 #include "sky/engine/public/platform/Platform.h" | 52 #include "sky/engine/public/platform/Platform.h" |
| 56 #include "sky/engine/wtf/BitArray.h" | 53 #include "sky/engine/wtf/BitArray.h" |
| 57 #include "sky/engine/wtf/HashSet.h" | 54 #include "sky/engine/wtf/HashSet.h" |
| 58 | 55 |
| (...skipping 14 matching lines...) Expand all Loading... |
| 73 case CSSPropertyWebkitTransformOriginX: | 70 case CSSPropertyWebkitTransformOriginX: |
| 74 case CSSPropertyWebkitTransformOriginY: | 71 case CSSPropertyWebkitTransformOriginY: |
| 75 case CSSPropertyWebkitTransformOriginZ: | 72 case CSSPropertyWebkitTransformOriginZ: |
| 76 return CSSPropertyTransformOrigin; | 73 return CSSPropertyTransformOrigin; |
| 77 default: | 74 default: |
| 78 break; | 75 break; |
| 79 } | 76 } |
| 80 return property; | 77 return property; |
| 81 } | 78 } |
| 82 | 79 |
| 83 static void resolveKeyframes(StyleResolver* resolver, Element* element, const El
ement& parentElement, const RenderStyle& style, RenderStyle* parentStyle, const
AtomicString& name, TimingFunction* defaultTimingFunction, | |
| 84 AnimatableValueKeyframeVector& keyframes) | |
| 85 { | |
| 86 // When the element is null, use its parent for scoping purposes. | |
| 87 const Element* elementForScoping = element ? element : &parentElement; | |
| 88 const StyleRuleKeyframes* keyframesRule = CSSAnimations::matchScopedKeyframe
sRule(resolver, elementForScoping, name); | |
| 89 if (!keyframesRule) | |
| 90 return; | |
| 91 | |
| 92 const Vector<RefPtr<StyleKeyframe> >& styleKeyframes = keyframesRule->keyfra
mes(); | |
| 93 if (styleKeyframes.isEmpty()) | |
| 94 return; | |
| 95 | |
| 96 // Construct and populate the style for each keyframe | |
| 97 for (size_t i = 0; i < styleKeyframes.size(); ++i) { | |
| 98 const StyleKeyframe* styleKeyframe = styleKeyframes[i].get(); | |
| 99 // It's OK to pass a null element here. | |
| 100 RefPtr<RenderStyle> keyframeStyle = resolver->styleForKeyframe(element,
style, parentStyle, styleKeyframe, name); | |
| 101 RefPtr<AnimatableValueKeyframe> keyframe = AnimatableValueKeyframe::crea
te(); | |
| 102 const Vector<double>& offsets = styleKeyframe->keys(); | |
| 103 ASSERT(!offsets.isEmpty()); | |
| 104 keyframe->setOffset(offsets[0]); | |
| 105 keyframe->setEasing(defaultTimingFunction); | |
| 106 const StylePropertySet& properties = styleKeyframe->properties(); | |
| 107 for (unsigned j = 0; j < properties.propertyCount(); j++) { | |
| 108 CSSPropertyID property = propertyForAnimation(properties.propertyAt(
j).id()); | |
| 109 if (property == CSSPropertyAnimationTimingFunction) { | |
| 110 CSSValue* value = properties.propertyAt(j).value(); | |
| 111 RefPtr<TimingFunction> timingFunction; | |
| 112 if (value->isInheritedValue() && parentStyle->animations()) | |
| 113 timingFunction = parentStyle->animations()->timingFunctionLi
st()[0]; | |
| 114 else if (value->isInheritedValue() || value->isInitialValue()) | |
| 115 timingFunction = CSSTimingData::initialTimingFunction(); | |
| 116 else | |
| 117 timingFunction = CSSToStyleMap::mapAnimationTimingFunction(t
oCSSValueList(value)->item(0)); | |
| 118 keyframe->setEasing(timingFunction.release()); | |
| 119 } else if (CSSPropertyMetadata::isAnimatableProperty(property)) { | |
| 120 keyframe->setPropertyValue(property, CSSAnimatableValueFactory::
create(property, *keyframeStyle).get()); | |
| 121 } | |
| 122 } | |
| 123 keyframes.append(keyframe); | |
| 124 // The last keyframe specified at a given offset is used. | |
| 125 for (size_t j = 1; j < offsets.size(); ++j) { | |
| 126 keyframes.append(toAnimatableValueKeyframe(keyframe->cloneWithOffset
(offsets[j]).get())); | |
| 127 } | |
| 128 } | |
| 129 ASSERT(!keyframes.isEmpty()); | |
| 130 | |
| 131 // Remove duplicate keyframes. In CSS the last keyframe at a given offset ta
kes priority. | |
| 132 std::stable_sort(keyframes.begin(), keyframes.end(), Keyframe::compareOffset
s); | |
| 133 size_t targetIndex = 0; | |
| 134 for (size_t i = 1; i < keyframes.size(); i++) { | |
| 135 if (keyframes[i]->offset() != keyframes[targetIndex]->offset()) | |
| 136 targetIndex++; | |
| 137 if (targetIndex != i) | |
| 138 keyframes[targetIndex] = keyframes[i]; | |
| 139 } | |
| 140 keyframes.shrink(targetIndex + 1); | |
| 141 | |
| 142 // Add 0% and 100% keyframes if absent. | |
| 143 RefPtr<AnimatableValueKeyframe> startKeyframe = keyframes[0]; | |
| 144 if (startKeyframe->offset()) { | |
| 145 startKeyframe = AnimatableValueKeyframe::create(); | |
| 146 startKeyframe->setOffset(0); | |
| 147 startKeyframe->setEasing(defaultTimingFunction); | |
| 148 keyframes.prepend(startKeyframe); | |
| 149 } | |
| 150 RefPtr<AnimatableValueKeyframe> endKeyframe = keyframes[keyframes.size() - 1
]; | |
| 151 if (endKeyframe->offset() != 1) { | |
| 152 endKeyframe = AnimatableValueKeyframe::create(); | |
| 153 endKeyframe->setOffset(1); | |
| 154 endKeyframe->setEasing(defaultTimingFunction); | |
| 155 keyframes.append(endKeyframe); | |
| 156 } | |
| 157 ASSERT(keyframes.size() >= 2); | |
| 158 ASSERT(!keyframes.first()->offset()); | |
| 159 ASSERT(keyframes.last()->offset() == 1); | |
| 160 | |
| 161 // Snapshot current property values for 0% and 100% if missing. | |
| 162 PropertySet allProperties; | |
| 163 size_t numKeyframes = keyframes.size(); | |
| 164 for (size_t i = 0; i < numKeyframes; i++) { | |
| 165 const PropertySet& keyframeProperties = keyframes[i]->properties(); | |
| 166 for (PropertySet::const_iterator iter = keyframeProperties.begin(); iter
!= keyframeProperties.end(); ++iter) | |
| 167 allProperties.add(*iter); | |
| 168 } | |
| 169 const PropertySet& startKeyframeProperties = startKeyframe->properties(); | |
| 170 const PropertySet& endKeyframeProperties = endKeyframe->properties(); | |
| 171 bool missingStartValues = startKeyframeProperties.size() < allProperties.siz
e(); | |
| 172 bool missingEndValues = endKeyframeProperties.size() < allProperties.size(); | |
| 173 if (missingStartValues || missingEndValues) { | |
| 174 for (PropertySet::const_iterator iter = allProperties.begin(); iter != a
llProperties.end(); ++iter) { | |
| 175 const CSSPropertyID property = *iter; | |
| 176 bool startNeedsValue = missingStartValues && !startKeyframePropertie
s.contains(property); | |
| 177 bool endNeedsValue = missingEndValues && !endKeyframeProperties.cont
ains(property); | |
| 178 if (!startNeedsValue && !endNeedsValue) | |
| 179 continue; | |
| 180 RefPtr<AnimatableValue> snapshotValue = CSSAnimatableValueFactory::c
reate(property, style); | |
| 181 if (startNeedsValue) | |
| 182 startKeyframe->setPropertyValue(property, snapshotValue.get()); | |
| 183 if (endNeedsValue) | |
| 184 endKeyframe->setPropertyValue(property, snapshotValue.get()); | |
| 185 } | |
| 186 } | |
| 187 ASSERT(startKeyframe->properties().size() == allProperties.size()); | |
| 188 ASSERT(endKeyframe->properties().size() == allProperties.size()); | |
| 189 } | |
| 190 | |
| 191 } // namespace | 80 } // namespace |
| 192 | 81 |
| 193 const StyleRuleKeyframes* CSSAnimations::matchScopedKeyframesRule(StyleResolver*
resolver, const Element* element, String animationName) | |
| 194 { | |
| 195 // FIXME: This is all implementation detail of style resolver, CSSAnimations
shouldn't be reaching into any of it. | |
| 196 Vector<RawPtr<ScopedStyleResolver>, 8> stack; | |
| 197 resolver->styleTreeResolveScopedKeyframesRules(element, stack); | |
| 198 if (stack.isEmpty()) | |
| 199 return 0; | |
| 200 | |
| 201 for (size_t i = 0; i < stack.size(); ++i) { | |
| 202 if (const StyleRuleKeyframes* keyframesRule = stack.at(i)->keyframeStyle
sForAnimation(animationName)) | |
| 203 return keyframesRule; | |
| 204 } | |
| 205 return 0; | |
| 206 } | |
| 207 | |
| 208 CSSAnimations::CSSAnimations() | 82 CSSAnimations::CSSAnimations() |
| 209 { | 83 { |
| 210 } | 84 } |
| 211 | 85 |
| 212 PassOwnPtr<CSSAnimationUpdate> CSSAnimations::calculateUpdate(Element* element,
const Element& parentElement, const RenderStyle& style, RenderStyle* parentStyle
, StyleResolver* resolver) | 86 PassOwnPtr<CSSAnimationUpdate> CSSAnimations::calculateUpdate(Element* element,
const Element& parentElement, const RenderStyle& style, RenderStyle* parentStyle
) |
| 213 { | 87 { |
| 214 OwnPtr<CSSAnimationUpdate> update = adoptPtr(new CSSAnimationUpdate()); | 88 OwnPtr<CSSAnimationUpdate> update = adoptPtr(new CSSAnimationUpdate()); |
| 215 calculateAnimationUpdate(update.get(), element, parentElement, style, parent
Style, resolver); | |
| 216 calculateAnimationActiveInterpolations(update.get(), element, parentElement.
document().timeline().currentTimeInternal()); | 89 calculateAnimationActiveInterpolations(update.get(), element, parentElement.
document().timeline().currentTimeInternal()); |
| 217 calculateTransitionUpdate(update.get(), element, style); | 90 calculateTransitionUpdate(update.get(), element, style); |
| 218 calculateTransitionActiveInterpolations(update.get(), element, parentElement
.document().timeline().currentTimeInternal()); | 91 calculateTransitionActiveInterpolations(update.get(), element, parentElement
.document().timeline().currentTimeInternal()); |
| 219 return update->isEmpty() ? nullptr : update.release(); | 92 return update->isEmpty() ? nullptr : update.release(); |
| 220 } | 93 } |
| 221 | 94 |
| 222 void CSSAnimations::calculateAnimationUpdate(CSSAnimationUpdate* update, Element
* element, const Element& parentElement, const RenderStyle& style, RenderStyle*
parentStyle, StyleResolver* resolver) | |
| 223 { | |
| 224 const ActiveAnimations* activeAnimations = element ? element->activeAnimatio
ns() : 0; | |
| 225 | |
| 226 #if !ENABLE(ASSERT) | |
| 227 // If we're in an animation style change, no animations can have started, be
en cancelled or changed play state. | |
| 228 // When ASSERT is enabled, we verify this optimization. | |
| 229 if (activeAnimations && activeAnimations->isAnimationStyleChange()) | |
| 230 return; | |
| 231 #endif | |
| 232 | |
| 233 const CSSAnimationData* animationData = style.animations(); | |
| 234 const CSSAnimations* cssAnimations = activeAnimations ? &activeAnimations->c
ssAnimations() : 0; | |
| 235 | |
| 236 HashSet<AtomicString> inactive; | |
| 237 if (cssAnimations) | |
| 238 for (AnimationMap::const_iterator iter = cssAnimations->m_animations.beg
in(); iter != cssAnimations->m_animations.end(); ++iter) | |
| 239 inactive.add(iter->key); | |
| 240 | |
| 241 if (style.display() != NONE) { | |
| 242 for (size_t i = 0; animationData && i < animationData->nameList().size()
; ++i) { | |
| 243 AtomicString animationName(animationData->nameList()[i]); | |
| 244 if (animationName == CSSAnimationData::initialName()) | |
| 245 continue; | |
| 246 | |
| 247 bool isPaused = CSSTimingData::getRepeated(animationData->playStateL
ist(), i) == AnimPlayStatePaused; | |
| 248 | |
| 249 // Keyframes and animation properties are snapshotted when the | |
| 250 // animation starts, so we don't need to track changes to these, | |
| 251 // with the exception of play-state. | |
| 252 if (cssAnimations) { | |
| 253 AnimationMap::const_iterator existing(cssAnimations->m_animation
s.find(animationName)); | |
| 254 if (existing != cssAnimations->m_animations.end()) { | |
| 255 inactive.remove(animationName); | |
| 256 AnimationPlayer* player = existing->value.get(); | |
| 257 if (isPaused != player->paused()) { | |
| 258 ASSERT(!activeAnimations || !activeAnimations->isAnimati
onStyleChange()); | |
| 259 update->toggleAnimationPaused(animationName); | |
| 260 } | |
| 261 continue; | |
| 262 } | |
| 263 } | |
| 264 | |
| 265 Timing timing = animationData->convertToTiming(i); | |
| 266 RefPtr<TimingFunction> keyframeTimingFunction = timing.timingFunctio
n; | |
| 267 timing.timingFunction = Timing::defaults().timingFunction; | |
| 268 AnimatableValueKeyframeVector resolvedKeyframes; | |
| 269 resolveKeyframes(resolver, element, parentElement, style, parentStyl
e, animationName, keyframeTimingFunction.get(), resolvedKeyframes); | |
| 270 if (!resolvedKeyframes.isEmpty()) { | |
| 271 ASSERT(!activeAnimations || !activeAnimations->isAnimationStyleC
hange()); | |
| 272 update->startAnimation(animationName, InertAnimation::create(Ani
matableValueKeyframeEffectModel::create(resolvedKeyframes), timing, isPaused)); | |
| 273 } | |
| 274 } | |
| 275 } | |
| 276 | |
| 277 ASSERT(inactive.isEmpty() || cssAnimations); | |
| 278 for (HashSet<AtomicString>::const_iterator iter = inactive.begin(); iter !=
inactive.end(); ++iter) { | |
| 279 ASSERT(!activeAnimations || !activeAnimations->isAnimationStyleChange())
; | |
| 280 update->cancelAnimation(*iter, *cssAnimations->m_animations.get(*iter)); | |
| 281 } | |
| 282 } | |
| 283 | |
| 284 void CSSAnimations::maybeApplyPendingUpdate(Element* element) | 95 void CSSAnimations::maybeApplyPendingUpdate(Element* element) |
| 285 { | 96 { |
| 286 if (!m_pendingUpdate) { | 97 if (!m_pendingUpdate) { |
| 287 m_previousActiveInterpolationsForAnimations.clear(); | 98 m_previousActiveInterpolationsForAnimations.clear(); |
| 288 return; | 99 return; |
| 289 } | 100 } |
| 290 | 101 |
| 291 OwnPtr<CSSAnimationUpdate> update = m_pendingUpdate.release(); | 102 OwnPtr<CSSAnimationUpdate> update = m_pendingUpdate.release(); |
| 292 | 103 |
| 293 m_previousActiveInterpolationsForAnimations.swap(update->activeInterpolation
sForAnimations()); | 104 m_previousActiveInterpolationsForAnimations.swap(update->activeInterpolation
sForAnimations()); |
| (...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 488 m_animations.clear(); | 299 m_animations.clear(); |
| 489 m_transitions.clear(); | 300 m_transitions.clear(); |
| 490 m_pendingUpdate = nullptr; | 301 m_pendingUpdate = nullptr; |
| 491 } | 302 } |
| 492 | 303 |
| 493 void CSSAnimations::calculateAnimationActiveInterpolations(CSSAnimationUpdate* u
pdate, const Element* element, double timelineCurrentTime) | 304 void CSSAnimations::calculateAnimationActiveInterpolations(CSSAnimationUpdate* u
pdate, const Element* element, double timelineCurrentTime) |
| 494 { | 305 { |
| 495 ActiveAnimations* activeAnimations = element ? element->activeAnimations() :
0; | 306 ActiveAnimations* activeAnimations = element ? element->activeAnimations() :
0; |
| 496 AnimationStack* animationStack = activeAnimations ? &activeAnimations->defau
ltStack() : 0; | 307 AnimationStack* animationStack = activeAnimations ? &activeAnimations->defau
ltStack() : 0; |
| 497 | 308 |
| 498 if (update->newAnimations().isEmpty() && update->cancelledAnimationAnimation
Players().isEmpty()) { | 309 HashMap<CSSPropertyID, RefPtr<Interpolation> > activeInterpolationsForAnimat
ions(AnimationStack::activeInterpolations(animationStack, 0, 0, Animation::Defau
ltPriority, timelineCurrentTime)); |
| 499 HashMap<CSSPropertyID, RefPtr<Interpolation> > activeInterpolationsForAn
imations(AnimationStack::activeInterpolations(animationStack, 0, 0, Animation::D
efaultPriority, timelineCurrentTime)); | |
| 500 update->adoptActiveInterpolationsForAnimations(activeInterpolationsForAn
imations); | |
| 501 return; | |
| 502 } | |
| 503 | |
| 504 Vector<RawPtr<InertAnimation> > newAnimations; | |
| 505 for (size_t i = 0; i < update->newAnimations().size(); ++i) { | |
| 506 newAnimations.append(update->newAnimations()[i].animation.get()); | |
| 507 } | |
| 508 HashMap<CSSPropertyID, RefPtr<Interpolation> > activeInterpolationsForAnimat
ions(AnimationStack::activeInterpolations(animationStack, &newAnimations, &updat
e->cancelledAnimationAnimationPlayers(), Animation::DefaultPriority, timelineCur
rentTime)); | |
| 509 update->adoptActiveInterpolationsForAnimations(activeInterpolationsForAnimat
ions); | 310 update->adoptActiveInterpolationsForAnimations(activeInterpolationsForAnimat
ions); |
| 510 } | 311 } |
| 511 | 312 |
| 512 void CSSAnimations::calculateTransitionActiveInterpolations(CSSAnimationUpdate*
update, const Element* element, double timelineCurrentTime) | 313 void CSSAnimations::calculateTransitionActiveInterpolations(CSSAnimationUpdate*
update, const Element* element, double timelineCurrentTime) |
| 513 { | 314 { |
| 514 ActiveAnimations* activeAnimations = element ? element->activeAnimations() :
0; | 315 ActiveAnimations* activeAnimations = element ? element->activeAnimations() :
0; |
| 515 AnimationStack* animationStack = activeAnimations ? &activeAnimations->defau
ltStack() : 0; | 316 AnimationStack* animationStack = activeAnimations ? &activeAnimations->defau
ltStack() : 0; |
| 516 | 317 |
| 517 HashMap<CSSPropertyID, RefPtr<Interpolation> > activeInterpolationsForTransi
tions; | 318 HashMap<CSSPropertyID, RefPtr<Interpolation> > activeInterpolationsForTransi
tions; |
| 518 if (update->newTransitions().isEmpty() && update->cancelledTransitions().isE
mpty()) { | 319 if (update->newTransitions().isEmpty() && update->cancelledTransitions().isE
mpty()) { |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 634 case CSSPropertyTransitionDuration: | 435 case CSSPropertyTransitionDuration: |
| 635 case CSSPropertyTransitionProperty: | 436 case CSSPropertyTransitionProperty: |
| 636 case CSSPropertyTransitionTimingFunction: | 437 case CSSPropertyTransitionTimingFunction: |
| 637 return false; | 438 return false; |
| 638 default: | 439 default: |
| 639 return true; | 440 return true; |
| 640 } | 441 } |
| 641 } | 442 } |
| 642 | 443 |
| 643 } // namespace blink | 444 } // namespace blink |
| OLD | NEW |