Changeset 252911 in webkit
- Timestamp:
- Nov 27, 2019 11:38:43 AM (4 years ago)
- Location:
- trunk
- Files:
-
- 1 deleted
- 15 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r252910 r252911 1 2019-11-27 Antoine Quint <graouts@apple.com> 2 3 REGRESSION(r252455): imported/w3c/web-platform-tests/dom/events/Event-dispatch-on-disabled-elements.html fails on iOS and WK1 4 https://bugs.webkit.org/show_bug.cgi?id=204272 5 <rdar://problem/57253742> 6 7 Reviewed by Dean Jackson. 8 9 Removing this specific expectation for WK1 since it now behaves just like the other configurations. 10 11 * platform/mac-wk1/imported/w3c/web-platform-tests/dom/events/Event-dispatch-on-disabled-elements-expected.txt: Removed. 12 1 13 2019-11-27 Jonathan Bedard <jbedard@apple.com> 2 14 -
trunk/Source/WebCore/ChangeLog
r252909 r252911 1 2019-11-27 Antoine Quint <graouts@apple.com> 2 3 REGRESSION(r252455): imported/w3c/web-platform-tests/dom/events/Event-dispatch-on-disabled-elements.html fails on iOS and WK1 4 https://bugs.webkit.org/show_bug.cgi?id=204272 5 <rdar://problem/57253742> 6 7 Reviewed by Dean Jackson. 8 9 Events for declarative animations are dispatched using a MainThreadGenericEventQueue which dispatches enqueued events asynchronously. When a declarative 10 animation would be canceled, AnimationTimeline::cancelDeclarativeAnimation() would be called and would enqueue a "transitioncancel" or "animationcancel" 11 event (depending on the animation type) by virtue of calling DeclarativeAnimation::cancelFromStyle(), and would also call AnimationTimeline::removeAnimation() 12 right after. However, calling AnimationTimeline::removeAnimation() could have the side effect of removing the last reference to the DeclarativeAnimation 13 object, which would destroy its attached MainThreadGenericEventQueue before it had the time to dispatch the queued "transitioncancel" or "animationcancel" 14 event. 15 16 The call to AnimationTimeline::removeAnimation() in AnimationTimeline::cancelDeclarativeAnimation() is actually unnecessary. Simply canceling the animation 17 via DeclarativeAnimation::cancelFromStyle() will end up calling AnimationTimeline::removeAnimation() the next time animations are updated, which will leave 18 time for the cancel events to be dispatched. So all we need to do is remove AnimationTimeline::cancelDeclarativeAnimation() and replace its call sites with 19 simple calls to DeclarativeAnimation::cancelFromStyle(). 20 21 Making this change broke a test however: imported/w3c/web-platform-tests/css/css-animations/Document-getAnimations.tentative.html. We actually passed that 22 test by chance without implementing the feature required to make it work. We now implement the correct way to track a global position for an animation by 23 only setting one for declarative animations once they are disassociated with their owning element and have a non-idle play state. 24 25 And a few other tests broke: animations/animation-shorthand-name-order.html, imported/w3c/web-platform-tests/css/css-animations/animationevent-types.html 26 and webanimations/css-animations.html. The reason for those tests being broken was that not calling AnimationTimeline::removeAnimation() instantly as CSS 27 Animations were canceled also meant that the KeyframeEffectStack for the targeted element wasn't updated. To solve this, we added the animationTimingDidChange() 28 method on KeyframeEffect which is called whenever timing on the owning Animation changes, so for instance when cancel() is called as we cancel a CSS 29 Animation. That way we ensure we add and remove KeyframeEffect instances from the KeyframeEffectStack as the animation becomes relevant, which is now 30 an added condition checked by KeyframeEffectStack::addEffect(). 31 32 Finally, this revealed an issue in KeyframeEffectStack::ensureEffectsAreSorted() where we would consider CSSTransition and CSSAnimation objects to be 33 representative of a CSS Transition or CSS Animation even after the relationship with their owning element had been severed. We now correctly check that 34 relationship is intact and otherwise consider those animations just like any other animation. 35 36 * animation/AnimationTimeline.cpp: 37 (WebCore::AnimationTimeline::animationTimingDidChange): 38 (WebCore::AnimationTimeline::updateGlobalPosition): 39 (WebCore::AnimationTimeline::removeDeclarativeAnimationFromListsForOwningElement): 40 (WebCore::AnimationTimeline::updateCSSAnimationsForElement): 41 (WebCore::AnimationTimeline::updateCSSTransitionsForElementAndProperty): 42 (WebCore::AnimationTimeline::updateCSSTransitionsForElement): 43 (WebCore::AnimationTimeline::cancelDeclarativeAnimation): Deleted. 44 * animation/AnimationTimeline.h: 45 * animation/CSSAnimation.cpp: 46 (WebCore::CSSAnimation::syncPropertiesWithBackingAnimation): 47 * animation/CSSTransition.cpp: 48 (WebCore::CSSTransition::setTimingProperties): 49 * animation/DeclarativeAnimation.cpp: 50 (WebCore::DeclarativeAnimation::canHaveGlobalPosition): 51 * animation/DeclarativeAnimation.h: 52 * animation/DocumentTimeline.cpp: 53 (WebCore::DocumentTimeline::getAnimations const): 54 * animation/KeyframeEffect.cpp: 55 (WebCore::KeyframeEffect::animationTimelineDidChange): 56 (WebCore::KeyframeEffect::animationTimingDidChange): 57 (WebCore::KeyframeEffect::updateEffectStackMembership): 58 (WebCore::KeyframeEffect::setAnimation): 59 (WebCore::KeyframeEffect::setTarget): 60 * animation/KeyframeEffect.h: 61 * animation/KeyframeEffectStack.cpp: 62 (WebCore::KeyframeEffectStack::addEffect): 63 (WebCore::KeyframeEffectStack::ensureEffectsAreSorted): 64 * animation/KeyframeEffectStack.h: 65 * animation/WebAnimation.cpp: 66 (WebCore::WebAnimation::timingDidChange): 67 * animation/WebAnimation.h: 68 (WebCore::WebAnimation::canHaveGlobalPosition): 69 1 70 2019-11-27 James Darpinian <jdarpinian@chromium.org> 2 71 -
trunk/Source/WebCore/animation/AnimationTimeline.cpp
r252527 r252911 63 63 void AnimationTimeline::animationTimingDidChange(WebAnimation& animation) 64 64 { 65 updateGlobalPosition(animation); 66 65 67 if (m_animations.add(&animation)) { 66 animation.setGlobalPosition(m_allAnimations.size());67 68 m_allAnimations.append(makeWeakPtr(&animation)); 68 69 auto* timeline = animation.timeline(); … … 70 71 timeline->removeAnimation(animation); 71 72 } 73 } 74 75 void AnimationTimeline::updateGlobalPosition(WebAnimation& animation) 76 { 77 static uint64_t s_globalPosition = 0; 78 if (!animation.globalPosition() && animation.canHaveGlobalPosition()) 79 animation.setGlobalPosition(++s_globalPosition); 72 80 } 73 81 … … 157 165 auto& cssAnimationsByName = iterator->value; 158 166 auto& name = downcast<CSSAnimation>(animation).animationName(); 159 cssAnimationsByName.remove(name); 160 if (cssAnimationsByName.isEmpty()) 161 m_elementToCSSAnimationByName.remove(&element); 167 if (cssAnimationsByName.get(name) == &animation) { 168 cssAnimationsByName.remove(name); 169 if (cssAnimationsByName.isEmpty()) 170 m_elementToCSSAnimationByName.remove(&element); 171 } 162 172 } 163 173 } else if (is<CSSTransition>(animation)) { … … 253 263 if (m_elementToCSSAnimationByName.contains(&element)) { 254 264 for (const auto& cssAnimationsByNameMapItem : m_elementToCSSAnimationByName.take(&element)) 255 c ancelDeclarativeAnimation(*cssAnimationsByNameMapItem.value);265 cssAnimationsByNameMapItem.value->cancelFromStyle(); 256 266 } 257 267 element.ensureKeyframeEffectStack().setCSSAnimationNames(WTFMove(animationNames)); … … 282 292 auto& currentAnimation = currentAnimations->animation(i); 283 293 auto& name = currentAnimation.name(); 284 animationNames.append(name);285 294 if (namesOfPreviousAnimations.contains(name)) { 286 295 // We've found the name of this animation in our list of previous animations, this means we've already … … 289 298 if (auto cssAnimation = cssAnimationsByName.get(name)) 290 299 cssAnimation->setBackingAnimation(currentAnimation); 300 animationNames.append(name); 291 301 } else if (shouldConsiderAnimation(element, currentAnimation)) { 292 302 // Otherwise we are dealing with a new animation name and must create a CSSAnimation for it. 293 303 cssAnimationsByName.set(name, CSSAnimation::create(element, currentAnimation, currentStyle, afterChangeStyle)); 304 animationNames.append(name); 294 305 } 295 306 // Remove the name of this animation from our list since it's now known to be current. … … 302 313 for (const auto& nameOfAnimationToRemove : namesOfPreviousAnimations) { 303 314 if (auto animation = cssAnimationsByName.take(nameOfAnimationToRemove)) 304 cancelDeclarativeAnimation(*animation);315 animation->cancelFromStyle(); 305 316 } 306 317 … … 473 484 // 1. If the current value of the property in the running transition is equal to the value of the property in the after-change style, 474 485 // or if these two values cannot be interpolated, then implementations must cancel the running transition. 475 cancelDeclarativeAnimation(*previouslyRunningTransition);486 previouslyRunningTransition->cancelFromStyle(); 476 487 } else if (transitionCombinedDuration(matchingBackingAnimation) <= 0.0 || !CSSPropertyAnimation::canPropertyBeInterpolated(property, &previouslyRunningTransitionCurrentStyle, &afterChangeStyle)) { 477 488 // 2. Otherwise, if the combined duration is less than or equal to 0s, or if the current value of the property in the running transition 478 489 // cannot be interpolated with the value of the property in the after-change style, then implementations must cancel the running transition. 479 cancelDeclarativeAnimation(*previouslyRunningTransition);490 previouslyRunningTransition->cancelFromStyle(); 480 491 } else if (CSSPropertyAnimation::propertiesEqual(property, &previouslyRunningTransition->reversingAdjustedStartStyle(), &afterChangeStyle)) { 481 492 // 3. Otherwise, if the reversing-adjusted start value of the running transition is the same as the value of the property in the after-change 482 493 // style (see the section on reversing of transitions for why these case exists), implementations must cancel the running transition 483 cancelDeclarativeAnimation(*previouslyRunningTransition);494 previouslyRunningTransition->cancelFromStyle(); 484 495 485 496 // and start a new transition whose: … … 507 518 } else { 508 519 // 4. Otherwise, implementations must cancel the running transition 509 cancelDeclarativeAnimation(*previouslyRunningTransition);520 previouslyRunningTransition->cancelFromStyle(); 510 521 511 522 // and start a new transition whose: … … 531 542 if (m_elementToRunningCSSTransitionByCSSPropertyID.contains(&element)) { 532 543 for (const auto& cssTransitionsByCSSPropertyIDMapItem : m_elementToRunningCSSTransitionByCSSPropertyID.take(&element)) 533 c ancelDeclarativeAnimation(*cssTransitionsByCSSPropertyIDMapItem.value);544 cssTransitionsByCSSPropertyIDMapItem.value->cancelFromStyle(); 534 545 } 535 546 return; … … 569 580 } 570 581 571 void AnimationTimeline::cancelDeclarativeAnimation(DeclarativeAnimation& animation)572 {573 animation.cancelFromStyle();574 removeAnimation(animation);575 m_allAnimations.removeFirst(&animation);576 }577 578 582 } // namespace WebCore -
trunk/Source/WebCore/animation/AnimationTimeline.h
r251543 r252911 83 83 84 84 private: 85 void updateGlobalPosition(WebAnimation&); 85 86 RefPtr<WebAnimation> cssAnimationForElementAndProperty(Element&, CSSPropertyID); 86 87 PropertyToTransitionMap& ensureRunningTransitionsByProperty(Element&); 87 88 void updateCSSTransitionsForElementAndProperty(Element&, CSSPropertyID, const RenderStyle& currentStyle, const RenderStyle& afterChangeStyle, PropertyToTransitionMap&, PropertyToTransitionMap&, const MonotonicTime); 88 void cancelDeclarativeAnimation(DeclarativeAnimation&);89 89 90 90 ElementToAnimationsMap m_elementToAnimationsMap; -
trunk/Source/WebCore/animation/CSSAnimation.cpp
r251785 r252911 98 98 animationEffect->setIterationDuration(Seconds(animation.duration())); 99 99 animationEffect->updateStaticTimingProperties(); 100 effectTimingDidChange(); 100 101 101 102 // Synchronize the play state -
trunk/Source/WebCore/animation/CSSTransition.cpp
r251785 r252911 75 75 animationEffect->setTimingFunction(backingAnimation().timingFunction()); 76 76 animationEffect->updateStaticTimingProperties(); 77 effectTimingDidChange(); 77 78 78 79 unsuspendEffectInvalidation(); -
trunk/Source/WebCore/animation/DeclarativeAnimation.cpp
r251840 r252911 70 70 m_eventQueue->close(); 71 71 } 72 } 73 74 bool DeclarativeAnimation::canHaveGlobalPosition() 75 { 76 // https://drafts.csswg.org/css-animations-2/#animation-composite-order 77 // https://drafts.csswg.org/css-transitions-2/#animation-composite-order 78 // CSS Animations and CSS Transitions generated using the markup defined in this specification are not added 79 // to the global animation list when they are created. Instead, these animations are appended to the global 80 // animation list at the first moment when they transition out of the idle play state after being disassociated 81 // from their owning element. 82 return !m_owningElement && playState() != WebAnimation::PlayState::Idle; 72 83 } 73 84 -
trunk/Source/WebCore/animation/DeclarativeAnimation.h
r251742 r252911 68 68 void tick() override; 69 69 70 bool canHaveGlobalPosition() final; 71 70 72 protected: 71 73 DeclarativeAnimation(Element&, const Animation&); -
trunk/Source/WebCore/animation/DocumentTimeline.cpp
r252723 r252911 183 183 }); 184 184 185 std::sort(webAnimations.begin(), webAnimations.end(), [](auto& lhs, auto& rhs) { 186 return lhs->globalPosition() < rhs->globalPosition(); 187 }); 188 185 189 // Finally, we can concatenate the sorted CSS Transitions, CSS Animations and Web Animations in their relative composite order. 186 190 Vector<RefPtr<WebAnimation>> animations; -
trunk/Source/WebCore/animation/KeyframeEffect.cpp
r252724 r252911 997 997 998 998 if (timeline) 999 m_ target->ensureKeyframeEffectStack().addEffect(*this);1000 else 999 m_inTargetEffectStack = m_target->ensureKeyframeEffectStack().addEffect(*this); 1000 else { 1001 1001 m_target->ensureKeyframeEffectStack().removeEffect(*this); 1002 m_inTargetEffectStack = false; 1003 } 1004 } 1005 1006 void KeyframeEffect::animationTimingDidChange() 1007 { 1008 updateEffectStackMembership(); 1009 } 1010 1011 void KeyframeEffect::updateEffectStackMembership() 1012 { 1013 if (!m_target) 1014 return; 1015 1016 bool isRelevant = animation() && animation()->isRelevant(); 1017 if (isRelevant && !m_inTargetEffectStack) 1018 m_inTargetEffectStack = m_target->ensureKeyframeEffectStack().addEffect(*this); 1019 else if (!isRelevant && m_inTargetEffectStack) { 1020 m_target->ensureKeyframeEffectStack().removeEffect(*this); 1021 m_inTargetEffectStack = false; 1022 } 1002 1023 } 1003 1024 … … 1006 1027 bool animationChanged = animation != this->animation(); 1007 1028 AnimationEffect::setAnimation(animation); 1008 if (m_target && animationChanged) { 1009 if (animation) 1010 m_target->ensureKeyframeEffectStack().addEffect(*this); 1011 else 1012 m_target->ensureKeyframeEffectStack().removeEffect(*this); 1013 } 1029 1030 if (!animationChanged) 1031 return; 1032 1033 if (animation) 1034 animation->updateRelevance(); 1035 updateEffectStackMembership(); 1014 1036 } 1015 1037 … … 1034 1056 invalidateElement(previousTarget.get()); 1035 1057 1036 if (previousTarget) 1058 if (previousTarget) { 1037 1059 previousTarget->ensureKeyframeEffectStack().removeEffect(*this); 1060 m_inTargetEffectStack = false; 1061 } 1038 1062 if (m_target) 1039 m_ target->ensureKeyframeEffectStack().addEffect(*this);1063 m_inTargetEffectStack = m_target->ensureKeyframeEffectStack().addEffect(*this); 1040 1064 } 1041 1065 -
trunk/Source/WebCore/animation/KeyframeEffect.h
r252554 r252911 117 117 void animationSuspensionStateDidChange(bool) final; 118 118 void animationTimelineDidChange(AnimationTimeline*) final; 119 void animationTimingDidChange(); 119 120 void applyPendingAcceleratedActions(); 120 121 bool isRunningAccelerated() const { return m_lastRecordedAcceleratedAction != AcceleratedAction::Stop; } … … 148 149 enum class BlendingKeyframesSource : uint8_t { CSSAnimation, CSSTransition, WebAnimation }; 149 150 151 void updateEffectStackMembership(); 150 152 void copyPropertiesFromSource(Ref<KeyframeEffect>&&); 151 153 ExceptionOr<void> processKeyframes(JSC::JSGlobalObject&, JSC::Strong<JSC::JSObject>&&); … … 189 191 #endif 190 192 bool m_colorFilterFunctionListsMatch { false }; 193 bool m_inTargetEffectStack { false }; 191 194 }; 192 195 -
trunk/Source/WebCore/animation/KeyframeEffectStack.cpp
r252253 r252911 43 43 } 44 44 45 voidKeyframeEffectStack::addEffect(KeyframeEffect& effect)45 bool KeyframeEffectStack::addEffect(KeyframeEffect& effect) 46 46 { 47 // To qualify for membership in an effect stack, an effect must have a target, an animation and a timeline.47 // To qualify for membership in an effect stack, an effect must have a target, an animation, a timeline and be relevant. 48 48 // This method will be called in WebAnimation and KeyframeEffect as those properties change. 49 if (!effect.target() || !effect.animation() || !effect.animation()->timeline() )50 return ;49 if (!effect.target() || !effect.animation() || !effect.animation()->timeline() || !effect.animation()->isRelevant()) 50 return false; 51 51 52 52 m_effects.append(makeWeakPtr(&effect)); 53 53 m_isSorted = false; 54 return true; 54 55 } 55 56 … … 77 78 ASSERT(rhsAnimation); 78 79 80 bool lhsHasOwningElement = is<DeclarativeAnimation>(lhsAnimation) && downcast<DeclarativeAnimation>(lhsAnimation)->owningElement(); 81 bool rhsHasOwningElement = is<DeclarativeAnimation>(rhsAnimation) && downcast<DeclarativeAnimation>(rhsAnimation)->owningElement(); 82 79 83 // CSS Transitions sort first. 80 bool lhsIsCSSTransition = is<CSSTransition>(lhsAnimation);81 bool rhsIsCSSTransition = is<CSSTransition>(rhsAnimation);84 bool lhsIsCSSTransition = lhsHasOwningElement && is<CSSTransition>(lhsAnimation); 85 bool rhsIsCSSTransition = rhsHasOwningElement && is<CSSTransition>(rhsAnimation); 82 86 if (lhsIsCSSTransition || rhsIsCSSTransition) { 83 87 if (lhsIsCSSTransition == rhsIsCSSTransition) { … … 94 98 95 99 // CSS Animations sort next. 96 bool lhsIsCSSAnimation = is<CSSAnimation>(lhsAnimation);97 bool rhsIsCSSAnimation = is<CSSAnimation>(rhsAnimation);100 bool lhsIsCSSAnimation = lhsHasOwningElement && is<CSSAnimation>(lhsAnimation); 101 bool rhsIsCSSAnimation = rhsHasOwningElement && is<CSSAnimation>(rhsAnimation); 98 102 if (lhsIsCSSAnimation || rhsIsCSSAnimation) { 99 103 if (lhsIsCSSAnimation == rhsIsCSSAnimation) { -
trunk/Source/WebCore/animation/KeyframeEffectStack.h
r252253 r252911 39 39 ~KeyframeEffectStack(); 40 40 41 voidaddEffect(KeyframeEffect&);41 bool addEffect(KeyframeEffect&); 42 42 void removeEffect(KeyframeEffect&); 43 43 bool hasEffects() const { return !m_effects.isEmpty(); } -
trunk/Source/WebCore/animation/WebAnimation.cpp
r252723 r252911 722 722 m_shouldSkipUpdatingFinishedStateWhenResolving = false; 723 723 updateFinishedState(didSeek, synchronouslyNotify); 724 725 if (is<KeyframeEffect>(m_effect)) { 726 updateRelevance(); 727 downcast<KeyframeEffect>(*m_effect).animationTimingDidChange(); 728 } 729 724 730 if (m_timeline) 725 731 m_timeline->animationTimingDidChange(*this); -
trunk/Source/WebCore/animation/WebAnimation.h
r252007 r252911 121 121 bool isRunningAccelerated() const; 122 122 bool isRelevant() const { return m_isRelevant; } 123 void updateRelevance(); 123 124 void effectTimingDidChange(); 124 125 void suspendEffectInvalidation(); … … 130 131 void enqueueAnimationPlaybackEvent(const AtomString&, Optional<Seconds>, Optional<Seconds>); 131 132 132 u nsignedglobalPosition() const { return m_globalPosition; }133 void setGlobalPosition(u nsignedglobalPosition) { m_globalPosition = globalPosition; }133 uint64_t globalPosition() const { return m_globalPosition; } 134 void setGlobalPosition(uint64_t globalPosition) { m_globalPosition = globalPosition; } 134 135 135 136 bool hasPendingActivity() const final; 137 138 virtual bool canHaveGlobalPosition() { return true; } 136 139 137 140 // ContextDestructionObserver. … … 170 173 bool isEffectInvalidationSuspended() { return m_suspendCount; } 171 174 bool computeRelevance(); 172 void updateRelevance();173 175 void invalidateEffect(); 174 176 double effectivePlaybackRate() const; … … 195 197 TimeToRunPendingTask m_timeToRunPendingPauseTask { TimeToRunPendingTask::NotScheduled }; 196 198 ReplaceState m_replaceState { ReplaceState::Active }; 197 u nsigned m_globalPosition;199 uint64_t m_globalPosition { 0 }; 198 200 199 201 // ActiveDOMObject.
Note: See TracChangeset
for help on using the changeset viewer.