Changeset 252253 in webkit
- Timestamp:
- Nov 8, 2019 12:40:57 PM (4 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 2 added
- 15 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r252245 r252253 1 2019-11-08 Antoine Quint <graouts@apple.com> 2 3 [Web Animations] Use a keyframe effect stack to resolve animations on an element 4 https://bugs.webkit.org/show_bug.cgi?id=204010 5 6 Reviewed by Dean Jackson. 7 8 Until now, when resolving animations for an element, we would call animationsForElement() during each resolution which 9 means doing several hash table lookups to locate the various classes of animations for that given element, sorting each 10 of those animations and inserting them into a new Vector. 11 12 We now use a KeyframeEffectStack which keeps a list of KeyframeEffect objects that apply to a given target, provided the 13 effect also has a valid animation and that animation has a valid timeline, all pre-conditions for that effect to produce 14 an animated value. Any time one of those pre-conditions change, we update the membership of that effect in the stack. 15 The KeyframeEffectStack is a new member of ElementRareData. 16 17 Now, each time we resolve an animation for an element, we iterate over the KeyframeEffect objects returned by calling 18 sortEffects() on the KeyframeEffectStack which will sort the stack's effects only if a new effect had been added since 19 the last iteration, which means that simple animations that are not mutated will require sorting of the stack just once, 20 and the addition of several animations in a single animation frame will require sorting just once as well. 21 22 It was also found while doing this work that Style::TreeResolver::createAnimatedElementUpdate would call RenderStyle::clonePtr() 23 for any element that was part of a document containing a timeline, regardless of whether that element had any animations. Now 24 we check whether that element's KeyframeEffectStack contains any effects prior to cloning the style. 25 26 No tests or changes to existed test expectations as this should not yield any change in behavior. 27 28 * Sources.txt: Add the new KeyframeEffectStack. 29 * WebCore.xcodeproj/project.pbxproj: 30 * animation/AnimationEffect.h: 31 (WebCore::AnimationEffect::setAnimation): 32 * animation/AnimationTimeline.cpp: 33 (WebCore::AnimationTimeline::removeAnimation): 34 (WebCore::AnimationTimeline::updateCSSAnimationsForElement): Since we need to know the order of CSS @keyframes rules listed in animation-name 35 when sorting effects, we must compile the ordered list of those @keyframe rules as we update CSS animations for an element and store it on its 36 KeyframeEffectStack. 37 * animation/DocumentTimeline.cpp: 38 (WebCore::DocumentTimeline::resolveAnimationsForElement): Deleted. Replaced by Element::applyKeyframeEffects(). 39 * animation/DocumentTimeline.h: 40 * animation/KeyframeEffect.cpp: 41 (WebCore::KeyframeEffect::animationTimelineDidChange): 42 (WebCore::KeyframeEffect::setAnimation): 43 (WebCore::KeyframeEffect::setTarget): 44 * animation/KeyframeEffect.h: 45 * animation/KeyframeEffectStack.cpp: Added. 46 (WebCore::KeyframeEffectStack::KeyframeEffectStack): 47 (WebCore::KeyframeEffectStack::~KeyframeEffectStack): 48 (WebCore::KeyframeEffectStack::addEffect): 49 (WebCore::KeyframeEffectStack::removeEffect): 50 (WebCore::KeyframeEffectStack::sortedEffects): 51 (WebCore::KeyframeEffectStack::ensureEffectsAreSorted): 52 (WebCore::KeyframeEffectStack::setCSSAnimationNames): 53 * animation/KeyframeEffectStack.h: Added. 54 (WebCore::KeyframeEffectStack::hasEffects const): 55 * animation/WebAnimation.cpp: 56 (WebCore::WebAnimation::setTimelineInternal): 57 (WebCore::WebAnimation::persist): 58 * dom/Element.cpp: 59 (WebCore::Element::ensureKeyframeEffectStack): 60 (WebCore::Element::hasKeyframeEffects const): 61 (WebCore::Element::applyKeyframeEffects): 62 * dom/Element.h: 63 * dom/ElementRareData.cpp: 64 * dom/ElementRareData.h: 65 (WebCore::ElementRareData::keyframeEffectStack): 66 (WebCore::ElementRareData::setKeyframeEffectStack): 67 * style/StyleTreeResolver.cpp: 68 (WebCore::Style::TreeResolver::createAnimatedElementUpdate): 69 1 70 2019-11-07 Dean Jackson <dino@apple.com> 2 71 -
trunk/Source/WebCore/Sources.txt
r252226 r252253 449 449 450 450 animation/AnimationEffect.cpp 451 animation/KeyframeEffectStack.cpp 451 452 animation/AnimationPlaybackEvent.cpp 452 453 animation/AnimationTimeline.cpp -
trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj
r252226 r252253 2093 2093 71A1B6081DEE5AD70073BCFB /* modern-media-controls-localized-strings.js in Resources */ = {isa = PBXBuildFile; fileRef = 71A1B6061DEE5A820073BCFB /* modern-media-controls-localized-strings.js */; }; 2094 2094 71A57DF2154BE25C0009D120 /* SVGPathUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = 71A57DF0154BE25C0009D120 /* SVGPathUtilities.h */; }; 2095 71A58196236F467600D81A24 /* KeyframeEffectStack.h in Headers */ = {isa = PBXBuildFile; fileRef = 71A58193236F466400D81A24 /* KeyframeEffectStack.h */; settings = {ATTRIBUTES = (Private, ); }; }; 2095 2096 71B28427203CEC4C0036AA5D /* JSCSSAnimation.h in Headers */ = {isa = PBXBuildFile; fileRef = 71B28426203CEC0D0036AA5D /* JSCSSAnimation.h */; settings = {ATTRIBUTES = (Private, ); }; }; 2096 2097 71B5AB2621F1D9F400376E5C /* PointerCaptureController.h in Headers */ = {isa = PBXBuildFile; fileRef = 71B5AB2421F1D9E200376E5C /* PointerCaptureController.h */; settings = {ATTRIBUTES = (Private, ); }; }; … … 9475 9476 71A57DEF154BE25C0009D120 /* SVGPathUtilities.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SVGPathUtilities.cpp; sourceTree = "<group>"; }; 9476 9477 71A57DF0154BE25C0009D120 /* SVGPathUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SVGPathUtilities.h; sourceTree = "<group>"; }; 9478 71A58193236F466400D81A24 /* KeyframeEffectStack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KeyframeEffectStack.h; sourceTree = "<group>"; }; 9479 71A58195236F466500D81A24 /* KeyframeEffectStack.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = KeyframeEffectStack.cpp; sourceTree = "<group>"; }; 9477 9480 71AEE4EB21B5A49C00DDB036 /* TouchAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TouchAction.h; sourceTree = "<group>"; }; 9478 9481 71B0460A1DD3C2EE00EE19CF /* status-support.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = "status-support.js"; sourceTree = "<group>"; }; … … 20855 20858 71247E321FEA5F7F008C08CE /* KeyframeEffectOptions.h */, 20856 20859 71247E301FEA5F7E008C08CE /* KeyframeEffectOptions.idl */, 20860 71A58195236F466500D81A24 /* KeyframeEffectStack.cpp */, 20861 71A58193236F466400D81A24 /* KeyframeEffectStack.h */, 20857 20862 7120733D216DFAF100C78329 /* OptionalEffectTiming.h */, 20858 20863 7120733F216DFAF200C78329 /* OptionalEffectTiming.idl */, … … 30669 30674 FDF6BAF9134A4C9800822920 /* JSOfflineAudioCompletionEvent.h in Headers */, 30670 30675 FDA9326716703BA9008982DC /* JSOfflineAudioContext.h in Headers */, 30671 E45BA6AA2374926C004DFC07 /* MatchedDeclarationsCache.h in Headers */,30672 30676 314877E61FAAB02500C05759 /* JSOffscreenCanvas.h in Headers */, 30673 30677 3140C5271FDF558200D2A873 /* JSOffscreenCanvasRenderingContext2D.h in Headers */, … … 31083 31087 71556CB41F9F09BA00E78D08 /* KeyframeEffect.h in Headers */, 31084 31088 71247E3A1FEA5F86008C08CE /* KeyframeEffectOptions.h in Headers */, 31089 71A58196236F467600D81A24 /* KeyframeEffectStack.h in Headers */, 31085 31090 BC5EBA110E823E4700B25965 /* KeyframeList.h in Headers */, 31086 31091 E15FF7D518C9553800FE4C87 /* KeypressCommand.h in Headers */, … … 31174 31179 9728C3141268E4390041E89B /* MarkupAccumulator.h in Headers */, 31175 31180 00C60E3F13D76D7E0092A275 /* MarkupTokenizerInlines.h in Headers */, 31181 E45BA6AA2374926C004DFC07 /* MatchedDeclarationsCache.h in Headers */, 31176 31182 FABE72F51059C1EB00D888CC /* MathMLAnnotationElement.h in Headers */, 31177 31183 FABE72F51059C1EB00D999DD /* MathMLElement.h in Headers */, -
trunk/Source/WebCore/animation/AnimationEffect.h
r251785 r252253 48 48 namespace WebCore { 49 49 50 class AnimationEffect : public RefCounted<AnimationEffect> {50 class AnimationEffect : public RefCounted<AnimationEffect>, public CanMakeWeakPtr<AnimationEffect> { 51 51 public: 52 52 virtual ~AnimationEffect(); … … 63 63 virtual void animationDidSeek() = 0; 64 64 virtual void animationSuspensionStateDidChange(bool) = 0; 65 virtual void animationTimelineDidChange(AnimationTimeline*) = 0; 65 66 66 67 WebAnimation* animation() const { return m_animation.get(); } 67 v oid setAnimation(WebAnimation* animation) { m_animation = makeWeakPtr(animation); }68 virtual void setAnimation(WebAnimation* animation) { m_animation = makeWeakPtr(animation); } 68 69 69 70 Seconds delay() const { return m_delay; } -
trunk/Source/WebCore/animation/AnimationTimeline.cpp
r251543 r252253 37 37 #include "Element.h" 38 38 #include "KeyframeEffect.h" 39 #include "KeyframeEffectStack.h" 39 40 #include "RenderStyle.h" 40 41 #include "RenderView.h" … … 76 77 m_animations.remove(&animation); 77 78 if (is<KeyframeEffect>(animation.effect())) { 78 if (auto* target = downcast<KeyframeEffect>(animation.effect())->target()) 79 if (auto* target = downcast<KeyframeEffect>(animation.effect())->target()) { 79 80 animationWasRemovedFromElement(animation, *target); 81 target->ensureKeyframeEffectStack().removeEffect(*downcast<KeyframeEffect>(animation.effect())); 82 } 80 83 } 81 84 } … … 244 247 void AnimationTimeline::updateCSSAnimationsForElement(Element& element, const RenderStyle* currentStyle, const RenderStyle& afterChangeStyle) 245 248 { 249 Vector<String> animationNames; 250 246 251 // In case this element is newly getting a "display: none" we need to cancel all of its animations and disregard new ones. 247 252 if (currentStyle && currentStyle->hasAnimations() && currentStyle->display() != DisplayType::None && afterChangeStyle.display() == DisplayType::None) { … … 250 255 cancelDeclarativeAnimation(*cssAnimationsByNameMapItem.value); 251 256 } 257 element.ensureKeyframeEffectStack().setCSSAnimationNames(WTFMove(animationNames)); 252 258 return; 253 259 } … … 276 282 auto& currentAnimation = currentAnimations->animation(i); 277 283 auto& name = currentAnimation.name(); 284 animationNames.append(name); 278 285 if (namesOfPreviousAnimations.contains(name)) { 279 286 // We've found the name of this animation in our list of previous animations, this means we've already … … 297 304 cancelDeclarativeAnimation(*animation); 298 305 } 306 307 element.ensureKeyframeEffectStack().setCSSAnimationNames(WTFMove(animationNames)); 299 308 } 300 309 -
trunk/Source/WebCore/animation/DocumentTimeline.cpp
r250839 r252253 29 29 #include "AnimationPlaybackEvent.h" 30 30 #include "CSSAnimation.h" 31 #include "CSSPropertyAnimation.h"32 31 #include "CSSTransition.h" 33 32 #include "DOMWindow.h" … … 674 673 } 675 674 676 bool DocumentTimeline::resolveAnimationsForElement(Element& element, RenderStyle& targetStyle)677 {678 bool hasNonAcceleratedAnimationProperty = false;679 680 for (const auto& animation : animationsForElement(element)) {681 animation->resolve(targetStyle);682 683 if (hasNonAcceleratedAnimationProperty)684 continue;685 686 auto* effect = animation->effect();687 if (!effect || !is<KeyframeEffect>(effect))688 continue;689 690 auto* keyframeEffect = downcast<KeyframeEffect>(effect);691 for (auto cssPropertyId : keyframeEffect->animatedProperties()) {692 if (!CSSPropertyAnimation::animationOfPropertyIsAccelerated(cssPropertyId)) {693 hasNonAcceleratedAnimationProperty = true;694 break;695 }696 }697 }698 699 return !hasNonAcceleratedAnimationProperty;700 }701 702 675 bool DocumentTimeline::runningAnimationsForElementAreAllAccelerated(Element& element) const 703 676 { -
trunk/Source/WebCore/animation/DocumentTimeline.h
r250617 r252253 68 68 void applyPendingAcceleratedAnimations(); 69 69 bool runningAnimationsForElementAreAllAccelerated(Element&) const; 70 bool resolveAnimationsForElement(Element&, RenderStyle&);71 70 void detachFromDocument(); 72 71 -
trunk/Source/WebCore/animation/KeyframeEffect.cpp
r251959 r252253 45 45 #include "JSDOMConvert.h" 46 46 #include "JSKeyframeEffect.h" 47 #include "KeyframeEffectStack.h" 47 48 #include "RenderBox.h" 48 49 #include "RenderBoxModelObject.h" … … 991 992 } 992 993 994 void KeyframeEffect::animationTimelineDidChange(AnimationTimeline* timeline) 995 { 996 if (!m_target) 997 return; 998 999 if (timeline) 1000 m_target->ensureKeyframeEffectStack().addEffect(*this); 1001 else 1002 m_target->ensureKeyframeEffectStack().removeEffect(*this); 1003 } 1004 1005 void KeyframeEffect::setAnimation(WebAnimation* animation) 1006 { 1007 bool animationChanged = animation != this->animation(); 1008 AnimationEffect::setAnimation(animation); 1009 if (m_target && animationChanged) { 1010 if (animation) 1011 m_target->ensureKeyframeEffectStack().addEffect(*this); 1012 else 1013 m_target->ensureKeyframeEffectStack().removeEffect(*this); 1014 } 1015 } 1016 993 1017 void KeyframeEffect::setTarget(RefPtr<Element>&& newTarget) 994 1018 { … … 1010 1034 // any animated styles are removed immediately. 1011 1035 invalidateElement(previousTarget.get()); 1036 1037 if (previousTarget) 1038 previousTarget->ensureKeyframeEffectStack().removeEffect(*this); 1039 if (m_target) 1040 m_target->ensureKeyframeEffectStack().addEffect(*this); 1012 1041 } 1013 1042 -
trunk/Source/WebCore/animation/KeyframeEffect.h
r251706 r252253 115 115 void animationDidSeek() final; 116 116 void animationSuspensionStateDidChange(bool) final; 117 void animationTimelineDidChange(AnimationTimeline*) final; 117 118 void applyPendingAcceleratedActions(); 118 119 bool isRunningAccelerated() const { return m_lastRecordedAcceleratedAction != AcceleratedAction::Stop; } 119 120 bool hasPendingAcceleratedAction() const { return !m_pendingAcceleratedActions.isEmpty() && isRunningAccelerated(); } 121 122 void setAnimation(WebAnimation*) final; 120 123 121 124 RenderElement* renderer() const override; -
trunk/Source/WebCore/animation/WebAnimation.cpp
r252007 r252253 238 238 239 239 m_timeline = WTFMove(timeline); 240 241 if (m_effect) 242 m_effect->animationTimelineDidChange(m_timeline.get()); 240 243 } 241 244 … … 1259 1262 1260 1263 if (previousReplaceState == ReplaceState::Removed && m_timeline) { 1261 if (is<KeyframeEffect>(m_effect)) 1262 m_timeline->animationWasAddedToElement(*this, *downcast<KeyframeEffect>(m_effect.get())->target()); 1264 if (is<KeyframeEffect>(m_effect)) { 1265 auto& keyframeEffect = downcast<KeyframeEffect>(*m_effect); 1266 auto& target = *keyframeEffect.target(); 1267 m_timeline->animationWasAddedToElement(*this, target); 1268 target.ensureKeyframeEffectStack().addEffect(keyframeEffect); 1269 } 1263 1270 } 1264 1271 } -
trunk/Source/WebCore/dom/Element.cpp
r251425 r252253 32 32 #include "CSSAnimationController.h" 33 33 #include "CSSParser.h" 34 #include "CSSPropertyAnimation.h" 34 35 #include "Chrome.h" 35 36 #include "ChromeClient.h" … … 3678 3679 #endif 3679 3680 3681 KeyframeEffectStack& Element::ensureKeyframeEffectStack() 3682 { 3683 auto& rareData = ensureElementRareData(); 3684 if (!rareData.keyframeEffectStack()) 3685 rareData.setKeyframeEffectStack(makeUnique<KeyframeEffectStack>()); 3686 return *rareData.keyframeEffectStack(); 3687 } 3688 3689 bool Element::hasKeyframeEffects() const 3690 { 3691 if (!hasRareData()) 3692 return false; 3693 3694 auto* keyframeEffectStack = elementRareData()->keyframeEffectStack(); 3695 return keyframeEffectStack && keyframeEffectStack->hasEffects(); 3696 } 3697 3698 bool Element::applyKeyframeEffects(RenderStyle& targetStyle) 3699 { 3700 bool hasNonAcceleratedAnimationProperty = false; 3701 3702 for (const auto& effect : ensureKeyframeEffectStack().sortedEffects()) { 3703 ASSERT(effect->animation()); 3704 effect->animation()->resolve(targetStyle); 3705 3706 if (hasNonAcceleratedAnimationProperty) 3707 continue; 3708 3709 // FIXME: https://bugs.webkit.org/show_bug.cgi?id=204009 3710 // KeyframeEffectStack and KeyframeEffect should indicate whether it only contains accelerated animation properties 3711 for (auto cssPropertyId : effect->animatedProperties()) { 3712 if (!CSSPropertyAnimation::animationOfPropertyIsAccelerated(cssPropertyId)) { 3713 hasNonAcceleratedAnimationProperty = true; 3714 break; 3715 } 3716 } 3717 } 3718 3719 return !hasNonAcceleratedAnimationProperty; 3720 } 3721 3680 3722 #if ENABLE(RESIZE_OBSERVER) 3681 3723 void Element::disconnectFromResizeObservers() -
trunk/Source/WebCore/dom/Element.h
r251425 r252253 48 48 class IntSize; 49 49 class JSCustomElementInterface; 50 class KeyframeEffectStack; 50 51 class KeyboardEvent; 51 52 class Locale; … … 490 491 void clearHasCSSAnimation(); 491 492 493 KeyframeEffectStack& ensureKeyframeEffectStack(); 494 bool hasKeyframeEffects() const; 495 bool applyKeyframeEffects(RenderStyle&); 496 492 497 #if ENABLE(FULLSCREEN_API) 493 498 WEBCORE_EXPORT bool containsFullScreenElement() const; -
trunk/Source/WebCore/dom/ElementRareData.cpp
r250584 r252253 44 44 LayoutSize sizeForResizing; 45 45 IntPoint savedLayerScrollPosition; 46 void* pointers[1 0];46 void* pointers[11]; 47 47 #if ENABLE(INTERSECTION_OBSERVER) 48 48 void* intersectionObserverData; -
trunk/Source/WebCore/dom/ElementRareData.h
r250584 r252253 26 26 #include "DatasetDOMStringMap.h" 27 27 #include "IntersectionObserver.h" 28 #include "KeyframeEffectStack.h" 28 29 #include "NamedNodeMap.h" 29 30 #include "NodeRareData.h" … … 100 101 bool hasCSSAnimation() const { return m_hasCSSAnimation; } 101 102 void setHasCSSAnimation(bool value) { m_hasCSSAnimation = value; } 103 104 KeyframeEffectStack* keyframeEffectStack() { return m_keyframeEffectStack.get(); } 105 void setKeyframeEffectStack(std::unique_ptr<KeyframeEffectStack>&& keyframeEffectStack) { m_keyframeEffectStack = WTFMove(keyframeEffectStack); } 102 106 103 107 bool hasElementIdentifier() const { return m_hasElementIdentifier; } … … 187 191 #endif 188 192 193 std::unique_ptr<KeyframeEffectStack> m_keyframeEffectStack; 194 189 195 RefPtr<PseudoElement> m_beforePseudoElement; 190 196 RefPtr<PseudoElement> m_afterPseudoElement; -
trunk/Source/WebCore/style/StyleTreeResolver.cpp
r252208 r252253 318 318 } 319 319 320 if (auto timeline = m_document.existingTimeline()) {321 // Now we can update all Web animations, which will include CSS Animations as well322 // as animations created via the JS API.320 // Now we can update all Web animations, which will include CSS Animations as well 321 // as animations created via the JS API. 322 if (element.hasKeyframeEffects()) { 323 323 auto animatedStyle = RenderStyle::clonePtr(*newStyle); 324 shouldRecompositeLayer = timeline->resolveAnimationsForElement(element,*animatedStyle);324 shouldRecompositeLayer = element.applyKeyframeEffects(*animatedStyle); 325 325 newStyle = WTFMove(animatedStyle); 326 326 }
Note: See TracChangeset
for help on using the changeset viewer.