Changeset 66339 in webkit
- Timestamp:
- Aug 29, 2010 4:16:21 PM (14 years ago)
- Location:
- trunk
- Files:
-
- 6 added
- 12 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r66327 r66339 1 2010-08-29 Simon Fraser <simon.fraser@apple.com> 2 3 Reviewed by Darin Adler. 4 5 When properties are missing from animation keyframes, interpolate between those keyframes that specify them 6 https://bugs.webkit.org/show_bug.cgi?id=40794 7 8 Testcases for keyframes with missing properties; repeating and non-repeating. 9 10 * animations/missing-from-to-transforms.html: 11 * animations/missing-from-to.html: 12 * animations/missing-keyframe-properties-expected.txt: Added. 13 * animations/missing-keyframe-properties-repeating-expected.txt: Added. 14 * animations/missing-keyframe-properties-repeating.html: Added. 15 * animations/missing-keyframe-properties-timing-function-expected.txt: Added. 16 * animations/missing-keyframe-properties-timing-function.html: Added. 17 * animations/missing-keyframe-properties.html: Added. 18 1 19 2010-08-28 Darin Adler <darin@apple.com> 2 20 -
trunk/LayoutTests/animations/missing-from-to-transforms.html
r61933 r66339 90 90 91 91 runAnimationTest(expectedValues, function() { 92 if ( layoutTestController) {92 if (window.layoutTestController) { 93 93 if (layoutTestController.pauseAnimationAtTimeOnElementWithId("anim5", 0.1, "box5")) 94 94 result += "FAIL - box5 animation was running<br>"; -
trunk/LayoutTests/animations/missing-from-to.html
r61933 r66339 89 89 90 90 runAnimationTest(expectedValues, function() { 91 if ( layoutTestController) {91 if (window.layoutTestController) { 92 92 if (layoutTestController.pauseAnimationAtTimeOnElementWithId("anim5", 0.1, "box5")) 93 93 result += "FAIL - box5 animation was running<br>"; -
trunk/WebCore/ChangeLog
r66338 r66339 1 2010-08-29 Simon Fraser <simon.fraser@apple.com> 2 3 Reviewed by Darin Adler. 4 5 When properties are missing from animation keyframes, interpolate between those keyframes that specify them 6 https://bugs.webkit.org/show_bug.cgi?id=40794 7 8 When a property does not appear in all keyframes of a keyframe animation, we currently use the 9 value of that property from the unanimated style. That forces the author to use additional 10 keyframes for properties that need to "skip a keyframe", which is laborious. 11 12 With this change, properties are interpolated between the keyframes in which they appear. 13 This is equivalent to splitting each property out into its own set of keyframes. 14 15 Tests: animations/missing-keyframe-properties-repeating.html 16 animations/missing-keyframe-properties-timing-function.html 17 animations/missing-keyframe-properties.html 18 19 * css/CSSStyleSelector.h: 20 * css/CSSStyleSelector.cpp: 21 (WebCore::CSSStyleSelector::styleForKeyframe): Pass a KeyframeValue in so that we can 22 collect which properties are represented per keyframe. 23 (WebCore::CSSStyleSelector::keyframeStylesForAnimation): Keyframes are inserted into a 24 KeyframeList by object now, rather than by key and style. 25 26 * page/animation/AnimationBase.cpp: 27 (WebCore::AnimationBase::progress): Use AnimationDirectionAlternate for readability. 28 29 * page/animation/KeyframeAnimation.cpp: 30 (WebCore::KeyframeAnimation::fetchIntervalEndpointsForProperty): Renamed from getKeyframeAnimationInterval. 31 Use fractionalTime etc to match AnimationBase::progress(), and do lookups per-property. 32 Simplify the code that finds the relevant keyframe to do less work. 33 (WebCore::KeyframeAnimation::animate): Call fetchIntervalEndpointsForProperty() for each property, rather than just once for the 34 entire keyframe. 35 (WebCore::KeyframeAnimation::getAnimatedStyle): Ditto. 36 (WebCore::KeyframeAnimation::hasAnimationForProperty): FIXME comment. 37 38 * page/animation/KeyframeAnimation.h: Rename getKeyframeAnimationInterval() to fetchIntervalEndpointsForProperty(). 39 40 * rendering/RenderLayerBacking.cpp: 41 (WebCore::RenderLayerBacking::startAnimation): For hardware animations, only insert values 42 for keyframes which contain the property. 43 44 (WebCore::KeyframeList::KeyframeList): insert() takes a KeyframeValue now. 45 * rendering/style/KeyframeList.cpp: 46 (WebCore::KeyframeList::operator==): 47 (WebCore::KeyframeList::insert): Fix insert/replace logic, and ensure we maintain the 48 m_properties hash. 49 50 * rendering/style/KeyframeList.h: 51 (WebCore::KeyframeValue::KeyframeValue): Make members private, with accessors. 52 Add a m_properties HashSet for the properties animated in this keyframe. 53 54 1 55 2010-08-29 Csaba Osztrogonác <ossy@webkit.org> 2 56 -
trunk/WebCore/css/CSSStyleSelector.cpp
r66335 r66339 1374 1374 } 1375 1375 1376 PassRefPtr<RenderStyle> CSSStyleSelector::styleForKeyframe(const RenderStyle* elementStyle, const WebKitCSSKeyframeRule* keyframeRule, Keyframe List& list)1376 PassRefPtr<RenderStyle> CSSStyleSelector::styleForKeyframe(const RenderStyle* elementStyle, const WebKitCSSKeyframeRule* keyframeRule, KeyframeValue& keyframe) 1377 1377 { 1378 1378 if (keyframeRule->style()) … … 1411 1411 loadPendingImages(); 1412 1412 1413 // Add all the animating properties to the list1413 // Add all the animating properties to the keyframe. 1414 1414 if (keyframeRule->style()) { 1415 1415 CSSMutableStyleDeclaration::const_iterator end = keyframeRule->style()->end(); … … 1419 1419 // describes the timing function between this keyframe and the next. 1420 1420 if (property != CSSPropertyWebkitAnimationTimingFunction) 1421 list.addProperty(property);1421 keyframe.addProperty(property); 1422 1422 } 1423 1423 } … … 1440 1440 1441 1441 const WebKitCSSKeyframesRule* rule = m_keyframesRuleMap.find(list.animationName().impl()).get()->second.get(); 1442 RefPtr<RenderStyle> keyframeStyle;1443 1442 1444 1443 // Construct and populate the style for each keyframe … … 1449 1448 1450 1449 const WebKitCSSKeyframeRule* keyframeRule = rule->item(i); 1451 1452 keyframeStyle = styleForKeyframe(elementStyle, keyframeRule, list); 1450 1451 KeyframeValue keyframe(0, 0); 1452 keyframe.setStyle(styleForKeyframe(elementStyle, keyframeRule, keyframe)); 1453 1453 1454 1454 // Add this keyframe style to all the indicated key times … … 1456 1456 keyframeRule->getKeys(keys); 1457 1457 for (size_t keyIndex = 0; keyIndex < keys.size(); ++keyIndex) { 1458 float key = keys[keyIndex]; 1459 list.insert(key, keyframeStyle.get()); 1460 } 1461 keyframeStyle.release(); 1458 keyframe.setKey(keys[keyIndex]); 1459 list.insert(keyframe); 1460 } 1462 1461 } 1463 1462 … … 1465 1464 int initialListSize = list.size(); 1466 1465 if (initialListSize > 0 && list[0].key() != 0) { 1467 RefPtr<WebKitCSSKeyframeRule> keyframe = WebKitCSSKeyframeRule::create(); 1468 keyframe->setKeyText("0%"); 1469 keyframeStyle = styleForKeyframe(elementStyle, keyframe.get(), list); 1470 list.insert(0, keyframeStyle.release()); 1466 RefPtr<WebKitCSSKeyframeRule> keyframeRule = WebKitCSSKeyframeRule::create(); 1467 keyframeRule->setKeyText("0%"); 1468 KeyframeValue keyframe(0, 0); 1469 keyframe.setStyle(styleForKeyframe(elementStyle, keyframeRule.get(), keyframe)); 1470 list.insert(keyframe); 1471 1471 } 1472 1472 1473 1473 // If the 100% keyframe is missing, create it (but only if there is at least one other keyframe) 1474 1474 if (initialListSize > 0 && (list[list.size() - 1].key() != 1)) { 1475 RefPtr<WebKitCSSKeyframeRule> keyframe = WebKitCSSKeyframeRule::create(); 1476 keyframe->setKeyText("100%"); 1477 keyframeStyle = styleForKeyframe(elementStyle, keyframe.get(), list); 1478 list.insert(1, keyframeStyle.release()); 1475 RefPtr<WebKitCSSKeyframeRule> keyframeRule = WebKitCSSKeyframeRule::create(); 1476 keyframeRule->setKeyText("100%"); 1477 KeyframeValue keyframe(1, 0); 1478 keyframe.setStyle(styleForKeyframe(elementStyle, keyframeRule.get(), keyframe)); 1479 list.insert(keyframe); 1479 1480 } 1480 1481 } -
trunk/WebCore/css/CSSStyleSelector.h
r66334 r66339 60 60 class KURL; 61 61 class KeyframeList; 62 class KeyframeValue; 62 63 class MediaQueryEvaluator; 63 64 class Node; … … 115 116 RenderStyle* style() const { return m_style.get(); } 116 117 117 PassRefPtr<RenderStyle> styleForKeyframe(const RenderStyle*, const WebKitCSSKeyframeRule*, Keyframe List&);118 PassRefPtr<RenderStyle> styleForKeyframe(const RenderStyle*, const WebKitCSSKeyframeRule*, KeyframeValue&); 118 119 119 120 public: -
trunk/WebCore/page/animation/AnimationBase.cpp
r63862 r66339 1243 1243 fractionalTime -= integralTime; 1244 1244 1245 if ( m_animation->direction() && (integralTime & 1))1245 if ((m_animation->direction() == Animation::AnimationDirectionAlternate) && (integralTime & 1)) 1246 1246 fractionalTime = 1 - fractionalTime; 1247 1247 -
trunk/WebCore/page/animation/KeyframeAnimation.cpp
r66310 r66339 63 63 } 64 64 65 void KeyframeAnimation:: getKeyframeAnimationInterval(const RenderStyle*& fromStyle, const RenderStyle*& toStyle, double& prog) const65 void KeyframeAnimation::fetchIntervalEndpointsForProperty(int property, const RenderStyle*& fromStyle, const RenderStyle*& toStyle, double& prog) const 66 66 { 67 67 // Find the first key 68 68 double elapsedTime = getElapsedTime(); 69 69 70 double t = m_animation->duration() ? (elapsedTime / m_animation->duration()) : 1; 71 72 ASSERT(t >= 0); 73 if (t < 0) 74 t = 0; 75 76 int i = static_cast<int>(t); 77 t -= i; 78 if (m_animation->direction() && (i & 1)) 79 t = 1 - t; 70 double fractionalTime = m_animation->duration() ? (elapsedTime / m_animation->duration()) : 1; 71 72 ASSERT(fractionalTime >= 0); 73 if (fractionalTime < 0) 74 fractionalTime = 0; 75 76 // FIXME: share this code with AnimationBase::progress(). 77 int iteration = static_cast<int>(fractionalTime); 78 fractionalTime -= iteration; 79 80 bool reversing = (m_animation->direction() == Animation::AnimationDirectionAlternate) && (iteration & 1); 81 if (reversing) 82 fractionalTime = 1 - fractionalTime; 83 84 size_t numKeyframes = m_keyframes.size(); 85 if (!numKeyframes) 86 return; 87 88 ASSERT(!m_keyframes[0].key()); 89 ASSERT(m_keyframes[m_keyframes.size() - 1].key() == 1); 90 91 int prevIndex = -1; 92 int nextIndex = -1; 93 94 // FIXME: with a lot of keys, this linear search will be slow. We could binary search. 95 for (size_t i = 0; i < numKeyframes; ++i) { 96 const KeyframeValue& currKeyFrame = m_keyframes[i]; 97 98 if (!currKeyFrame.containsProperty(property)) 99 continue; 100 101 if (fractionalTime < currKeyFrame.key()) { 102 nextIndex = i; 103 break; 104 } 105 106 prevIndex = i; 107 } 80 108 81 109 double scale = 1; 82 110 double offset = 0; 83 size_t numKeyframes = m_keyframes.size(); 84 for (size_t i = 0; i < numKeyframes; ++i) { 85 const KeyframeValue& currentKeyframe = m_keyframes[i]; 86 if (t < currentKeyframe.key()) { 87 // The first key should always be 0, so we should never succeed on the first key 88 if (!fromStyle) 89 break; 90 scale = 1.0 / (currentKeyframe.key() - offset); 91 toStyle = currentKeyframe.style(); 92 break; 93 } 94 95 offset = currentKeyframe.key(); 96 fromStyle = currentKeyframe.style(); 97 } 98 99 if (!fromStyle || !toStyle) 100 return; 111 112 if (prevIndex == -1) 113 prevIndex = 0; 114 115 if (nextIndex == -1) 116 nextIndex = m_keyframes.size() - 1; 117 118 const KeyframeValue& prevKeyframe = m_keyframes[prevIndex]; 119 const KeyframeValue& nextKeyframe = m_keyframes[nextIndex]; 120 121 fromStyle = prevKeyframe.style(); 122 toStyle = nextKeyframe.style(); 123 124 offset = prevKeyframe.key(); 125 scale = 1.0 / (nextKeyframe.key() - prevKeyframe.key()); 101 126 102 127 const TimingFunction* timingFunction = 0; … … 133 158 if (waitingToStart() && m_animation->delay() > 0 && !m_animation->fillsBackwards()) 134 159 return; 135 136 // FIXME: we need to be more efficient about determining which keyframes we are animating between. 137 // We should cache the last pair or something. 138 139 // Get the from/to styles and progress between 140 const RenderStyle* fromStyle = 0; 141 const RenderStyle* toStyle = 0; 142 double progress; 143 getKeyframeAnimationInterval(fromStyle, toStyle, progress); 144 145 // If either style is 0 we have an invalid case, just stop the animation. 146 if (!fromStyle || !toStyle) { 160 161 // If we have no keyframes, don't animate. 162 if (!m_keyframes.size()) { 147 163 updateStateMachine(AnimationStateInputEndAnimation, -1); 148 164 return; … … 154 170 animatedStyle = RenderStyle::clone(targetStyle); 155 171 172 // FIXME: we need to be more efficient about determining which keyframes we are animating between. 173 // We should cache the last pair or something. 156 174 HashSet<int>::const_iterator endProperties = m_keyframes.endProperties(); 157 175 for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != endProperties; ++it) { 158 bool needsAnim = blendProperties(this, *it, animatedStyle.get(), fromStyle, toStyle, progress); 176 int property = *it; 177 178 // Get the from/to styles and progress between 179 const RenderStyle* fromStyle = 0; 180 const RenderStyle* toStyle = 0; 181 double progress; 182 fetchIntervalEndpointsForProperty(property, fromStyle, toStyle, progress); 183 184 bool needsAnim = blendProperties(this, property, animatedStyle.get(), fromStyle, toStyle, progress); 159 185 if (needsAnim) 160 186 setAnimating(); … … 177 203 return; 178 204 179 // Get the from/to styles and progress between 180 const RenderStyle* fromStyle = 0; 181 const RenderStyle* toStyle = 0; 182 double progress; 183 getKeyframeAnimationInterval(fromStyle, toStyle, progress); 184 185 // If either style is 0 we have an invalid case 186 if (!fromStyle || !toStyle) 205 if (!m_keyframes.size()) 187 206 return; 188 207 … … 191 210 192 211 HashSet<int>::const_iterator endProperties = m_keyframes.endProperties(); 193 for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != endProperties; ++it) 194 blendProperties(this, *it, animatedStyle.get(), fromStyle, toStyle, progress); 212 for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != endProperties; ++it) { 213 int property = *it; 214 215 // Get the from/to styles and progress between 216 const RenderStyle* fromStyle = 0; 217 const RenderStyle* toStyle = 0; 218 double progress; 219 fetchIntervalEndpointsForProperty(property, fromStyle, toStyle, progress); 220 221 blendProperties(this, property, animatedStyle.get(), fromStyle, toStyle, progress); 222 } 195 223 } 196 224 197 225 bool KeyframeAnimation::hasAnimationForProperty(int property) const 198 226 { 227 // FIXME: why not just m_keyframes.containsProperty()? 199 228 HashSet<int>::const_iterator end = m_keyframes.endProperties(); 200 229 for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != end; ++it) { -
trunk/WebCore/page/animation/KeyframeAnimation.h
r52017 r66339 83 83 virtual ~KeyframeAnimation(); 84 84 85 // Get the styles surrounding the current animation time and the progress between them86 void getKeyframeAnimationInterval(const RenderStyle*& fromStyle, const RenderStyle*& toStyle, double& progress) const;85 // Get the styles for the given property surrounding the current animation time and the progress between them. 86 void fetchIntervalEndpointsForProperty(int property, const RenderStyle*& fromStyle, const RenderStyle*& toStyle, double& progress) const; 87 87 88 88 // The keyframes that we are blending. -
trunk/WebCore/rendering/RenderLayerBacking.cpp
r66310 r66339 1127 1127 const TimingFunction* tf = keyframeStyle->hasAnimations() ? &((*keyframeStyle->animations()).animation(0)->timingFunction()) : 0; 1128 1128 1129 if ( hasTransform)1129 if (currentKeyframe.containsProperty(AnimatedPropertyWebkitTransform)) 1130 1130 transformVector.insert(new TransformAnimationValue(key, &(keyframeStyle->transform()), tf)); 1131 1131 1132 if ( hasOpacity)1132 if (currentKeyframe.containsProperty(AnimatedPropertyOpacity)) 1133 1133 opacityVector.insert(new FloatAnimationValue(key, keyframeStyle->opacity(), tf)); 1134 1134 } -
trunk/WebCore/rendering/style/KeyframeList.cpp
r37637 r66339 44 44 Vector<KeyframeValue>::const_iterator it2 = o.m_keyframes.begin(); 45 45 for (Vector<KeyframeValue>::const_iterator it1 = m_keyframes.begin(); it1 != m_keyframes.end(); ++it1) { 46 if (it1-> m_key != it2->m_key)46 if (it1->key() != it2->key()) 47 47 return false; 48 const RenderStyle& style1 = *it1-> m_style;49 const RenderStyle& style2 = *it2-> m_style;48 const RenderStyle& style1 = *it1->style(); 49 const RenderStyle& style2 = *it2->style(); 50 50 if (style1 != style2) 51 51 return false; … … 56 56 } 57 57 58 void KeyframeList::insert( float key, PassRefPtr<RenderStyle> style)58 void KeyframeList::insert(const KeyframeValue& keyframe) 59 59 { 60 if (key < 0 || key> 1)60 if (keyframe.key() < 0 || keyframe.key() > 1) 61 61 return; 62 62 63 int index = -1;64 63 bool inserted = false; 64 bool replaced = false; 65 65 for (size_t i = 0; i < m_keyframes.size(); ++i) { 66 if (m_keyframes[i].m_key == key) { 67 index = (int) i; 66 if (m_keyframes[i].key() == keyframe.key()) { 67 m_keyframes[i] = keyframe; 68 replaced = true; 68 69 break; 69 70 } 70 if (m_keyframes[i].m_key > key) { 71 72 if (m_keyframes[i].key() > keyframe.key()) { 71 73 // insert before 72 m_keyframes.insert(i, KeyframeValue());73 in dex = (int) i;74 m_keyframes.insert(i, keyframe); 75 inserted = true; 74 76 break; 75 77 } 76 78 } 77 79 78 if (index < 0) { 79 // append 80 index = (int) m_keyframes.size(); 81 m_keyframes.append(KeyframeValue()); 80 if (!replaced && !inserted) 81 m_keyframes.append(keyframe); 82 83 if (replaced) { 84 // We have to rebuild the properties list from scratch. 85 m_properties.clear(); 86 for (Vector<KeyframeValue>::const_iterator it = m_keyframes.begin(); it != m_keyframes.end(); ++it) { 87 const KeyframeValue& currKeyframe = *it; 88 for (HashSet<int>::const_iterator it = currKeyframe.properties().begin(); it != currKeyframe.properties().end(); ++it) 89 m_properties.add(*it); 90 } 91 } else { 92 for (HashSet<int>::const_iterator it = keyframe.properties().begin(); it != keyframe.properties().end(); ++it) 93 m_properties.add(*it); 82 94 } 83 84 m_keyframes[index].m_key = key;85 m_keyframes[index].m_style = style;86 95 } 87 96 -
trunk/WebCore/rendering/style/KeyframeList.h
r66310 r66339 38 38 class KeyframeValue { 39 39 public: 40 KeyframeValue() 41 : m_key(-1) 40 KeyframeValue(float key, PassRefPtr<RenderStyle> style) 41 : m_key(key) 42 , m_style(style) 42 43 { 43 44 } 44 45 46 void addProperty(int prop) { m_properties.add(prop); } 47 bool containsProperty(int prop) const { return m_properties.contains(prop); } 48 const HashSet<int>& properties() const { return m_properties; } 49 45 50 float key() const { return m_key; } 51 void setKey(float key) { m_key = key; } 52 46 53 const RenderStyle* style() const { return m_style.get(); } 54 void setStyle(PassRefPtr<RenderStyle> style) { m_style = style; } 47 55 56 private: 48 57 float m_key; 58 HashSet<int> m_properties; // The properties specified in this keyframe. 49 59 RefPtr<RenderStyle> m_style; 50 60 }; … … 56 66 , m_renderer(renderer) 57 67 { 58 insert( 0, 0);59 insert( 1, 0);68 insert(KeyframeValue(0, 0)); 69 insert(KeyframeValue(1, 0)); 60 70 } 61 71 ~KeyframeList(); … … 66 76 const AtomicString& animationName() const { return m_animationName; } 67 77 68 void insert( float key, PassRefPtr<RenderStyle> style);78 void insert(const KeyframeValue& keyframe); 69 79 70 80 void addProperty(int prop) { m_properties.add(prop); } … … 80 90 private: 81 91 AtomicString m_animationName; 82 Vector<KeyframeValue> m_keyframes; 83 HashSet<int> m_properties; 92 Vector<KeyframeValue> m_keyframes; // kept sorted by key 93 HashSet<int> m_properties; // the properties being animated 84 94 RenderObject* m_renderer; 85 95 };
Note: See TracChangeset
for help on using the changeset viewer.