Changeset 294391 in webkit
- Timestamp:
- May 18, 2022, 5:54:37 AM (4 years ago)
- Location:
- trunk
- Files:
-
- 8 edited
-
LayoutTests/webanimations/accelerated-animations-and-composite-expected.txt (modified) (1 diff)
-
LayoutTests/webanimations/accelerated-animations-and-composite.html (modified) (2 diffs)
-
Source/WebCore/animation/DocumentTimeline.cpp (modified) (2 diffs)
-
Source/WebCore/animation/KeyframeEffect.cpp (modified) (21 diffs)
-
Source/WebCore/animation/KeyframeEffect.h (modified) (7 diffs)
-
Source/WebCore/animation/KeyframeEffectStack.cpp (modified) (3 diffs)
-
Source/WebCore/animation/KeyframeEffectStack.h (modified) (2 diffs)
-
Source/WebCore/animation/WebAnimationTypes.h (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/webanimations/accelerated-animations-and-composite-expected.txt
r289598 r294391 6 6 PASS Setting 'composite' to 'add' on an animation lower down the stack should prevent replace animations with an implicity keyframe further up the stack to be accelerated 7 7 PASS Setting 'composite' to 'add' on an animation lower down the stack targeting a property that isn't accelerated should allow replace animations with implicit keyframes further up the stack to be accelerated 8 PASS Dynamically setting 'composite' on an effect should toggle acceleration 9 PASS Dynamically setting 'composite' on a keyframe should toggle acceleration 10 PASS Dynamically setting 'composite' to 'add' on an animation further up the stack should toggle acceleration on lower animations in the stack 11 PASS Dynamically setting 'composite' to 'add' on an animation lower down the stack should toggle acceleration but always allow replace animations further up the stack to be accelerated 12 PASS Dynamically setting 'composite' to 'add' on an animation lower down the stack should toggle acceleration on replace animations with an implicity keyframe further up the stack 13 PASS Dynamically setting 'composite' to 'add' on an animation lower down the stack targeting a property that isn't accelerated shouldn't prevent acceleration of animations with implicit keyframes further up the stack to be accelerated 14 PASS Adding a composing effect on top of an existing replace effect should prevent both effects from running accelerated 8 15 -
trunk/LayoutTests/webanimations/accelerated-animations-and-composite.html
r289605 r294391 84 84 )); 85 85 await Promise.all(animations.map(animation => animationReadyToAnimateAccelerated(animation))); 86 assert_equals(internals.acceleratedAnimationsForElement(target).length, 1);86 assert_equals(internals.acceleratedAnimationsForElement(target).length, 0); 87 87 }, "Setting 'composite' to 'add' on an animation lower down the stack should allow replace animations further up the stack to be accelerated"); 88 88 … … 124 124 }, "Setting 'composite' to 'add' on an animation lower down the stack targeting a property that isn't accelerated should allow replace animations with implicit keyframes further up the stack to be accelerated"); 125 125 126 // The following tests check the dynamic interruption and/or start of accelerated animations 127 // after changes made to other effects in the stack. 128 129 promise_test(async test => { 130 const target = createDiv(test); 131 const animation = target.animate({ transform: "translateX(100px)" }, duration); 132 133 await animationReadyToAnimateAccelerated(animation); 134 assert_equals(internals.acceleratedAnimationsForElement(target).length, 1); 135 136 // Setting the effect composition to "add" means that the animation should 137 // no longer be accelerated. 138 animation.effect.composite = "add"; 139 await animationReadyToAnimateAccelerated(animation); 140 assert_equals(internals.acceleratedAnimationsForElement(target).length, 0); 141 142 // Resetting the effect composition to "replace" means that the animation 143 // should be accelerated again. 144 animation.effect.composite = "replace"; 145 await animationReadyToAnimateAccelerated(animation); 146 assert_equals(internals.acceleratedAnimationsForElement(target).length, 1); 147 }, "Dynamically setting 'composite' on an effect should toggle acceleration"); 148 149 promise_test(async test => { 150 const keyframes = composite => [{ offset: 1, composite, transform: "translateX(100px)" }]; 151 152 const target = createDiv(test); 153 const animation = target.animate(keyframes("replace"), duration); 154 await animationReadyToAnimateAccelerated(animation); 155 assert_equals(internals.acceleratedAnimationsForElement(target).length, 1); 156 157 // Setting the keyframe composition to "add" means that the animation should 158 // no longer be accelerated. 159 animation.effect.setKeyframes(keyframes("add")); 160 await animationReadyToAnimateAccelerated(animation); 161 assert_equals(internals.acceleratedAnimationsForElement(target).length, 0); 162 163 // Resetting the keyframe composition to "replace" means that the animation 164 // should be accelerated again. 165 animation.effect.setKeyframes(keyframes("replace")); 166 await animationReadyToAnimateAccelerated(animation); 167 assert_equals(internals.acceleratedAnimationsForElement(target).length, 1); 168 }, "Dynamically setting 'composite' on a keyframe should toggle acceleration"); 169 170 promise_test(async test => { 171 const target = createDiv(test); 172 const animations = []; 173 174 animations.push(target.animate({ transform: "translateX(100px)" }, duration)); 175 animations.push(target.animate({ transform: "translateY(100px)" }, duration)); 176 177 await Promise.all(animations.map(animation => animationReadyToAnimateAccelerated(animation))); 178 assert_equals(internals.acceleratedAnimationsForElement(target).length, 2, "Step 1"); 179 180 // Make the second animation a composing animation. This will prevent the first animation 181 // from running accelerated as well. 182 animations[1].effect.composite = "add"; 183 await Promise.all(animations.map(animation => animationReadyToAnimateAccelerated(animation))); 184 assert_equals(internals.acceleratedAnimationsForElement(target).length, 0, "Step 2"); 185 186 // Reset to the original state. 187 animations[1].effect.composite = "replace"; 188 await Promise.all(animations.map(animation => animationReadyToAnimateAccelerated(animation))); 189 assert_equals(internals.acceleratedAnimationsForElement(target).length, 2, "Step 3"); 190 }, "Dynamically setting 'composite' to 'add' on an animation further up the stack should toggle acceleration on lower animations in the stack"); 191 192 promise_test(async test => { 193 const target = createDiv(test); 194 195 const animations = []; 196 animations.push(target.animate({ transform: "translateX(100px)" }, duration)); 197 animations.push(target.animate({ transform: ["none", "translateY(100px)"] }, duration)); 198 await Promise.all(animations.map(animation => animationReadyToAnimateAccelerated(animation))); 199 assert_equals(internals.acceleratedAnimationsForElement(target).length, 2); 200 201 // Make the first animation a composing animation. This will prevent the other animation from running accelerated. 202 animations[0].effect.composite = "add"; 203 await Promise.all(animations.map(animation => animationReadyToAnimateAccelerated(animation))); 204 assert_equals(internals.acceleratedAnimationsForElement(target).length, 0); 205 206 // Reset to the original state. 207 animations[0].effect.composite = "replace"; 208 await Promise.all(animations.map(animation => animationReadyToAnimateAccelerated(animation))); 209 assert_equals(internals.acceleratedAnimationsForElement(target).length, 2); 210 }, "Dynamically setting 'composite' to 'add' on an animation lower down the stack should toggle acceleration but always allow replace animations further up the stack to be accelerated"); 211 212 promise_test(async test => { 213 const target = createDiv(test); 214 const animations = []; 215 216 animations.push(target.animate({ transform: "translateX(100px)" }, duration)); 217 animations.push(target.animate({ transform: "translateX(100px)" }, duration)); 218 await Promise.all(animations.map(animation => animationReadyToAnimateAccelerated(animation))); 219 assert_equals(internals.acceleratedAnimationsForElement(target).length, 2); 220 221 // Make the first animation a composing animation. This will prevent both animations 222 // from running accelerated since the second animation uses the first animation as 223 // input due to using an implicit 0% keyframe. 224 animations[0].effect.composite = "add"; 225 await Promise.all(animations.map(animation => animationReadyToAnimateAccelerated(animation))); 226 assert_equals(internals.acceleratedAnimationsForElement(target).length, 0); 227 228 // Reset to the original state. 229 animations[0].effect.composite = "replace"; 230 await Promise.all(animations.map(animation => animationReadyToAnimateAccelerated(animation))); 231 assert_equals(internals.acceleratedAnimationsForElement(target).length, 2); 232 }, "Dynamically setting 'composite' to 'add' on an animation lower down the stack should toggle acceleration on replace animations with an implicity keyframe further up the stack"); 233 234 promise_test(async test => { 235 const target = createDiv(test); 236 const animations = []; 237 238 animations.push(target.animate({ marginLeft: "100px" }, duration)); 239 animations.push(target.animate({ transform: "translateX(100px)" }, duration)); 240 await Promise.all(animations.map(animation => animationReadyToAnimateAccelerated(animation))); 241 assert_equals(internals.acceleratedAnimationsForElement(target).length, 1); 242 243 // Make the first animation a composing animation. This should not prevent the other animation from running accelerated. 244 animations[0].effect.composite = "add"; 245 await Promise.all(animations.map(animation => animationReadyToAnimateAccelerated(animation))); 246 assert_equals(internals.acceleratedAnimationsForElement(target).length, 1); 247 248 // Reset to the original state. 249 animations[0].effect.composite = "replace"; 250 await Promise.all(animations.map(animation => animationReadyToAnimateAccelerated(animation))); 251 assert_equals(internals.acceleratedAnimationsForElement(target).length, 1); 252 }, "Dynamically setting 'composite' to 'add' on an animation lower down the stack targeting a property that isn't accelerated shouldn't prevent acceleration of animations with implicit keyframes further up the stack to be accelerated"); 253 254 promise_test(async test => { 255 const target = createDiv(test); 256 const animation = target.animate({ transform: "translateX(100px)" }, duration); 257 258 await animationReadyToAnimateAccelerated(animation); 259 assert_equals(internals.acceleratedAnimationsForElement(target).length, 1); 260 261 const composingAnimation = target.animate( 262 { transform: "translateY(100px)" }, 263 { composite: "add", duration } 264 ); 265 266 await animationReadyToAnimateAccelerated(composingAnimation); 267 assert_equals(internals.acceleratedAnimationsForElement(target).length, 0); 268 }, "Adding a composing effect on top of an existing replace effect should prevent both effects from running accelerated"); 269 126 270 </script> 127 271 </body> -
trunk/Source/WebCore/animation/DocumentTimeline.cpp
r291863 r294391 391 391 m_acceleratedAnimationsPendingRunningStateChange.clear(); 392 392 393 // Animations may fail to run accelerated for reasons private to GraphicsLayerCA. If that happens, and the animation394 // in question targets a transform-related property, we must prevent all other transform-related animations for this395 // element to run accelerated since we can't run some transform-related animations accelerated, and some not. To do396 // this, we keep a list of all KeyframeEffectStack objects containing an effect that failed to start a transform-related397 // animation so that we can return any transform-related accelerated animation to run non-accelerated.398 HashSet<KeyframeEffectStack*> effectStacksContainingEffectThatFailedToRunAcceleratedTransformRelatedAnimation;399 400 393 bool hasForcedLayout = false; 401 394 for (auto& animation : acceleratedAnimationsPendingRunningStateChange) { … … 407 400 if (!hasForcedLayout) 408 401 hasForcedLayout |= keyframeEffect.forceLayoutIfNeeded(); 409 auto pendingAccelerationActionResult = keyframeEffect.applyPendingAcceleratedActions(); 410 if (pendingAccelerationActionResult.contains(AcceleratedActionApplicationResult::TransformRelatedAnimationCannotBeAccelerated)) { 411 ASSERT(keyframeEffect.targetStyleable()); 412 ASSERT(keyframeEffect.targetStyleable()->keyframeEffectStack()); 413 effectStacksContainingEffectThatFailedToRunAcceleratedTransformRelatedAnimation.add(keyframeEffect.targetStyleable()->keyframeEffectStack()); 414 } 415 } 416 417 for (auto& effectStack : effectStacksContainingEffectThatFailedToRunAcceleratedTransformRelatedAnimation) 418 effectStack->stopAcceleratingTransformRelatedProperties(UseAcceleratedAction::No); 402 keyframeEffect.applyPendingAcceleratedActions(); 403 } 419 404 } 420 405 -
trunk/Source/WebCore/animation/KeyframeEffect.cpp
r293879 r294391 550 550 551 551 KeyframeEffect::KeyframeEffect(Element* target, PseudoId pseudoId) 552 : m_target(target) 552 : m_keyframesName(makeAtomString("keyframe-effect-"_s, UUID::createVersion4Weak())) 553 , m_target(target) 553 554 , m_pseudoId(pseudoId) 554 555 { … … 586 587 updateStaticTimingProperties(); 587 588 588 KeyframeList keyframeList(m akeAtomString("keyframe-effect-"_s, UUID::createVersion4Weak()));589 KeyframeList keyframeList(m_keyframesName); 589 590 keyframeList.copyKeyframes(source->m_blendingKeyframes); 590 591 setBlendingKeyframes(keyframeList); … … 812 813 return; 813 814 814 KeyframeList keyframeList(m akeAtomString("keyframe-effect-"_s, UUID::createVersion4Weak()));815 KeyframeList keyframeList(m_keyframesName); 815 816 auto& styleResolver = m_target->styleResolver(); 816 817 … … 901 902 void KeyframeEffect::setBlendingKeyframes(KeyframeList& blendingKeyframes) 902 903 { 904 CanBeAcceleratedMutationScope mutationScope(this); 905 903 906 m_blendingKeyframes = WTFMove(blendingKeyframes); 904 907 m_animatedProperties.clear(); … … 1038 1041 Style::loadPendingResources(*toStyle, *document(), m_target.get()); 1039 1042 1040 KeyframeList keyframeList(m akeAtomString("keyframe-effect-"_s, UUID::createVersion4Weak()));1043 KeyframeList keyframeList(m_keyframesName); 1041 1044 keyframeList.addProperty(property); 1042 1045 … … 1601 1604 bool KeyframeEffect::preventsAcceleration() const 1602 1605 { 1603 return m_acceleratedPropertiesState != AcceleratedProperties::None && !canBeAccelerated(); 1606 if (m_acceleratedPropertiesState == AcceleratedProperties::None) 1607 return false; 1608 1609 return !canBeAccelerated() || m_runningAccelerated == RunningAccelerated::Failed; 1604 1610 } 1605 1611 … … 1610 1616 return; 1611 1617 1612 if (!canBeAccelerated()) { 1613 // In the case where this animation is actively targeting a transform-related property and yet 1614 // cannot be accelerated, we must notify the effect stack such that any running accelerated 1615 // transform-related animation targeting this element reverts to running non-accelerated. 1616 if (isTargetingTransformRelatedProperty() 1617 && animation()->playState() == WebAnimation::PlayState::Running 1618 && getComputedTiming().phase == AnimationEffectPhase::Active) { 1619 ASSERT(targetStyleable()); 1620 ASSERT(targetStyleable()->keyframeEffectStack()); 1621 targetStyleable()->keyframeEffectStack()->stopAcceleratingTransformRelatedProperties(UseAcceleratedAction::Yes); 1622 } 1623 return; 1624 } 1618 if (!canBeAccelerated()) 1619 return; 1625 1620 1626 1621 auto computedTiming = getComputedTiming(); … … 1657 1652 void KeyframeEffect::addPendingAcceleratedAction(AcceleratedAction action) 1658 1653 { 1654 if (m_runningAccelerated == RunningAccelerated::Prevented || m_runningAccelerated == RunningAccelerated::Failed) 1655 return; 1656 1659 1657 if (action == m_lastRecordedAcceleratedAction) 1660 1658 return; … … 1678 1676 computeSomeKeyframesUseStepsTimingFunction(); 1679 1677 1680 if (isRunningAccelerated() || isAboutToRunAccelerated()) 1681 addPendingAcceleratedAction(canBeAccelerated() ? AcceleratedAction::UpdateTiming : AcceleratedAction::Stop); 1682 else if (canBeAccelerated()) 1678 if (isRunningAccelerated() || isAboutToRunAccelerated()) { 1679 if (canBeAccelerated()) 1680 addPendingAcceleratedAction(AcceleratedAction::UpdateTiming); 1681 else { 1682 abilityToBeAcceleratedDidChange(); 1683 addPendingAcceleratedAction(AcceleratedAction::Stop); 1684 } 1685 } else if (canBeAccelerated()) 1683 1686 m_runningAccelerated = RunningAccelerated::NotStarted; 1684 1687 } … … 1722 1725 } 1723 1726 1724 OptionSet<AcceleratedActionApplicationResult>KeyframeEffect::applyPendingAcceleratedActions()1725 { 1726 OptionSet<AcceleratedActionApplicationResult> result;1727 void KeyframeEffect::applyPendingAcceleratedActions() 1728 { 1729 CanBeAcceleratedMutationScope mutationScope(this); 1727 1730 1728 1731 // Once an accelerated animation has been committed, we no longer want to force a layout. … … 1732 1735 1733 1736 if (m_pendingAcceleratedActions.isEmpty()) 1734 return result;1737 return; 1735 1738 1736 1739 auto* renderer = this->renderer(); … … 1742 1745 m_runningAccelerated = RunningAccelerated::NotStarted; 1743 1746 } 1744 return result;1747 return; 1745 1748 } 1746 1749 … … 1752 1755 1753 1756 auto startAnimation = [&]() -> RunningAccelerated { 1754 if ( m_runningAccelerated == RunningAccelerated::Yes)1757 if (isRunningAccelerated()) 1755 1758 renderer->animationFinished(m_blendingKeyframes.animationName()); 1756 1757 if (!m_hasImplicitKeyframeForAcceleratedProperty)1758 return renderer->startAnimation(timeOffset, backingAnimationForCompositedRenderer(), m_blendingKeyframes) ? RunningAccelerated::Yes : RunningAccelerated::No;1759 1759 1760 1760 ASSERT(m_target); … … 1762 1762 ASSERT(effectStack); 1763 1763 1764 if (effectStack->containsEffectThatPreventsAccelerationOfEffect(*this)) 1765 return RunningAccelerated::No; 1764 if (!effectStack->allowsAcceleration()) 1765 return RunningAccelerated::Prevented; 1766 1767 if (!m_hasImplicitKeyframeForAcceleratedProperty) 1768 return renderer->startAnimation(timeOffset, backingAnimationForCompositedRenderer(), m_blendingKeyframes) ? RunningAccelerated::Yes : RunningAccelerated::Failed; 1766 1769 1767 1770 // We need to resolve all animations up to this point to ensure any forward-filling … … 1783 1786 explicitKeyframes.copyKeyframes(m_blendingKeyframes); 1784 1787 explicitKeyframes.fillImplicitKeyframes(*this, *underlyingStyle); 1785 return renderer->startAnimation(timeOffset, backingAnimationForCompositedRenderer(), explicitKeyframes) ? RunningAccelerated::Yes : RunningAccelerated:: No;1788 return renderer->startAnimation(timeOffset, backingAnimationForCompositedRenderer(), explicitKeyframes) ? RunningAccelerated::Yes : RunningAccelerated::Failed; 1786 1789 }; 1787 1790 … … 1790 1793 case AcceleratedAction::Play: 1791 1794 m_runningAccelerated = startAnimation(); 1792 LOG_WITH_STREAM(Animations, stream << "KeyframeEffect " << this << " applyPendingAcceleratedActions " << m_blendingKeyframes.animationName() << " Play, started accelerated: " << (m_runningAccelerated == RunningAccelerated::Yes));1793 if ( m_runningAccelerated == RunningAccelerated::No) {1795 LOG_WITH_STREAM(Animations, stream << "KeyframeEffect " << this << " applyPendingAcceleratedActions " << m_blendingKeyframes.animationName() << " Play, started accelerated: " << isRunningAccelerated()); 1796 if (!isRunningAccelerated()) { 1794 1797 m_lastRecordedAcceleratedAction = AcceleratedAction::Stop; 1795 if (isTargetingTransformRelatedProperty()) 1796 result.add(AcceleratedActionApplicationResult::TransformRelatedAnimationCannotBeAccelerated); 1797 return result; 1798 return; 1798 1799 } 1799 1800 break; … … 1803 1804 case AcceleratedAction::UpdateTiming: 1804 1805 m_runningAccelerated = startAnimation(); 1805 LOG_WITH_STREAM(Animations, stream << "KeyframeEffect " << this << " applyPendingAcceleratedActions " << m_blendingKeyframes.animationName() << " UpdateTiming, started accelerated: " << (m_runningAccelerated == RunningAccelerated::Yes));1806 LOG_WITH_STREAM(Animations, stream << "KeyframeEffect " << this << " applyPendingAcceleratedActions " << m_blendingKeyframes.animationName() << " UpdateTiming, started accelerated: " << isRunningAccelerated()); 1806 1807 if (animation()->playState() == WebAnimation::PlayState::Paused) 1807 1808 renderer->animationPaused(timeOffset, m_blendingKeyframes.animationName()); … … 1812 1813 if (!document()->renderTreeBeingDestroyed()) 1813 1814 m_target->invalidateStyleAndLayerComposition(); 1814 m_runningAccelerated = canBeAccelerated() ? RunningAccelerated::NotStarted : RunningAccelerated:: No;1815 m_runningAccelerated = canBeAccelerated() ? RunningAccelerated::NotStarted : RunningAccelerated::Prevented; 1815 1816 break; 1816 1817 case AcceleratedAction::TransformChange: … … 1820 1821 } 1821 1822 1822 if (m_runningAccelerated == RunningAccelerated::No && isTargetingTransformRelatedProperty()) 1823 result.add(AcceleratedActionApplicationResult::TransformRelatedAnimationCannotBeAccelerated); 1824 1825 return result; 1826 } 1827 1828 void KeyframeEffect::stopAcceleratingTransformRelatedProperties(UseAcceleratedAction useAcceleratedAction) 1829 { 1830 if (!isRunningAcceleratedTransformRelatedAnimation()) 1831 return; 1832 1833 if (useAcceleratedAction == UseAcceleratedAction::Yes) { 1834 addPendingAcceleratedAction(AcceleratedAction::Stop); 1835 return; 1836 } 1837 1838 auto* renderer = this->renderer(); 1839 if (!renderer || !renderer->isComposited()) 1840 return; 1841 1842 ASSERT(document()); 1843 renderer->animationFinished(m_blendingKeyframes.animationName()); 1844 if (!document()->renderTreeBeingDestroyed()) 1845 m_target->invalidateStyleAndLayerComposition(); 1846 1847 m_runningAccelerated = RunningAccelerated::No; 1823 return; 1848 1824 } 1849 1825 … … 2138 2114 return; 2139 2115 2116 CanBeAcceleratedMutationScope mutationScope(this); 2140 2117 m_compositeOperation = compositeOperation; 2141 2118 invalidate(); … … 2267 2244 } 2268 2245 2246 void KeyframeEffect::effectStackNoLongerPreventsAcceleration() 2247 { 2248 if (m_runningAccelerated == RunningAccelerated::Failed) 2249 return; 2250 2251 if (m_runningAccelerated == RunningAccelerated::Prevented) 2252 m_runningAccelerated = RunningAccelerated::NotStarted; 2253 2254 updateAcceleratedActions(); 2255 } 2256 2257 void KeyframeEffect::effectStackNoLongerAllowsAcceleration() 2258 { 2259 addPendingAcceleratedAction(AcceleratedAction::Stop); 2260 } 2261 2262 void KeyframeEffect::abilityToBeAcceleratedDidChange() 2263 { 2264 if (!m_inTargetEffectStack) 2265 return; 2266 2267 ASSERT(m_target); 2268 if (auto* effectStack = m_target->keyframeEffectStack(m_pseudoId)) 2269 effectStack->effectAbilityToBeAcceleratedDidChange(*this); 2270 } 2271 2272 KeyframeEffect::CanBeAcceleratedMutationScope::CanBeAcceleratedMutationScope(KeyframeEffect* effect) 2273 : m_effect(effect) 2274 { 2275 ASSERT(effect); 2276 m_couldOriginallyPreventAcceleration = effect->preventsAcceleration(); 2277 } 2278 2279 KeyframeEffect::CanBeAcceleratedMutationScope::~CanBeAcceleratedMutationScope() 2280 { 2281 if (m_effect && m_couldOriginallyPreventAcceleration != m_effect->preventsAcceleration()) 2282 m_effect->abilityToBeAcceleratedDidChange(); 2283 } 2284 2269 2285 } // namespace WebCore -
trunk/Source/WebCore/animation/KeyframeEffect.h
r293292 r294391 128 128 void transformRelatedPropertyDidChange(); 129 129 void propertyAffectingKeyframeResolutionDidChange(RenderStyle&, const Style::ResolutionContext&); 130 OptionSet<AcceleratedActionApplicationResult>applyPendingAcceleratedActions();130 void applyPendingAcceleratedActions(); 131 131 132 132 void willChangeRenderer(); … … 173 173 bool hasImplicitKeyframes() const; 174 174 175 void stopAcceleratingTransformRelatedProperties(UseAcceleratedAction);176 177 175 void keyframesRuleDidChange(); 178 176 177 bool canBeAccelerated() const; 179 178 bool preventsAcceleration() const; 179 void effectStackNoLongerPreventsAcceleration(); 180 void effectStackNoLongerAllowsAcceleration(); 180 181 181 182 static String CSSPropertyIDToIDLAttributeName(CSSPropertyID); … … 187 188 enum class BlendingKeyframesSource : uint8_t { CSSAnimation, CSSTransition, WebAnimation }; 188 189 enum class AcceleratedProperties : uint8_t { None, Some, All }; 189 enum class RunningAccelerated : uint8_t { NotStarted, Yes, No }; 190 enum class RunningAccelerated : uint8_t { NotStarted, Yes, Prevented, Failed }; 191 192 class CanBeAcceleratedMutationScope { 193 WTF_MAKE_NONCOPYABLE(CanBeAcceleratedMutationScope); 194 public: 195 CanBeAcceleratedMutationScope(KeyframeEffect*); 196 ~CanBeAcceleratedMutationScope(); 197 198 private: 199 KeyframeEffect* m_effect; 200 bool m_couldOriginallyPreventAcceleration; 201 }; 190 202 191 203 Document* document() const; … … 195 207 ExceptionOr<void> processKeyframes(JSC::JSGlobalObject&, Document&, JSC::Strong<JSC::JSObject>&&); 196 208 void addPendingAcceleratedAction(AcceleratedAction); 197 bool canBeAccelerated() const;198 209 bool isCompletelyAccelerated() const { return m_acceleratedPropertiesState == AcceleratedProperties::All; } 199 210 void updateAcceleratedActions(); … … 221 232 void computeHasImplicitKeyframeForAcceleratedProperty(); 222 233 void computeHasKeyframeComposingAcceleratedProperty(); 234 void abilityToBeAcceleratedDidChange(); 223 235 224 236 // AnimationEffect … … 234 246 std::optional<double> progressUntilNextStep(double) const final; 235 247 248 AtomString m_keyframesName; 236 249 KeyframeList m_blendingKeyframes { emptyAtom() }; 237 250 HashSet<CSSPropertyID> m_animatedProperties; … … 248 261 AcceleratedProperties m_acceleratedPropertiesState { AcceleratedProperties::None }; 249 262 AnimationEffectPhase m_phaseAtLastApplication { AnimationEffectPhase::Idle }; 250 RunningAccelerated m_runningAccelerated { RunningAccelerated::No };263 RunningAccelerated m_runningAccelerated { RunningAccelerated::NotStarted }; 251 264 bool m_needsForcedLayout { false }; 252 265 bool m_triggersStackingContext { false }; -
trunk/Source/WebCore/animation/KeyframeEffectStack.cpp
r290831 r294391 55 55 m_effects.append(effect); 56 56 m_isSorted = false; 57 58 if (m_effects.size() > 1 && effect.preventsAcceleration()) 59 stopAcceleratedAnimations(); 60 57 61 return true; 58 62 } … … 60 64 void KeyframeEffectStack::removeEffect(KeyframeEffect& effect) 61 65 { 62 m_effects.removeFirst(&effect); 66 auto removedEffect = m_effects.removeFirst(&effect); 67 if (removedEffect && !m_effects.isEmpty() && !effect.canBeAccelerated()) 68 startAcceleratedAnimationsIfPossible(); 63 69 } 64 70 … … 173 179 } 174 180 175 void KeyframeEffectStack::stopAcceleratingTransformRelatedProperties(UseAcceleratedAction useAcceleratedAction) 176 { 181 void KeyframeEffectStack::clearInvalidCSSAnimationNames() 182 { 183 m_invalidCSSAnimationNames.clear(); 184 } 185 186 bool KeyframeEffectStack::hasInvalidCSSAnimationNames() const 187 { 188 return !m_invalidCSSAnimationNames.isEmpty(); 189 } 190 191 bool KeyframeEffectStack::containsInvalidCSSAnimationName(const String& name) const 192 { 193 return m_invalidCSSAnimationNames.contains(name); 194 } 195 196 void KeyframeEffectStack::addInvalidCSSAnimationName(const String& name) 197 { 198 m_invalidCSSAnimationNames.add(name); 199 } 200 201 void KeyframeEffectStack::effectAbilityToBeAcceleratedDidChange(const KeyframeEffect& effect) 202 { 203 ASSERT(m_effects.contains(&effect)); 204 if (effect.preventsAcceleration()) 205 stopAcceleratedAnimations(); 206 else 207 startAcceleratedAnimationsIfPossible(); 208 } 209 210 bool KeyframeEffectStack::allowsAcceleration() const 211 { 212 // We could try and be a lot smarter here and do this on a per-property basis and 213 // account for fully replacing effects which could co-exist with effects that 214 // don't support acceleration lower in the stack, etc. But, if we are not able to run 215 // all effects that could support acceleration using acceleration, then we might 216 // as well not run any at all since we'll be updating effects for this stack 217 // for each animation frame. So for now, we simply return false if any effect in the 218 // stack is unable to be accelerated. 219 for (auto& effect : m_effects) { 220 if (effect->preventsAcceleration()) 221 return false; 222 } 223 return true; 224 } 225 226 void KeyframeEffectStack::startAcceleratedAnimationsIfPossible() 227 { 228 if (!allowsAcceleration()) 229 return; 230 177 231 for (auto& effect : m_effects) 178 effect->stopAcceleratingTransformRelatedProperties(useAcceleratedAction); 179 } 180 181 void KeyframeEffectStack::clearInvalidCSSAnimationNames() 182 { 183 m_invalidCSSAnimationNames.clear(); 184 } 185 186 bool KeyframeEffectStack::hasInvalidCSSAnimationNames() const 187 { 188 return !m_invalidCSSAnimationNames.isEmpty(); 189 } 190 191 bool KeyframeEffectStack::containsInvalidCSSAnimationName(const String& name) const 192 { 193 return m_invalidCSSAnimationNames.contains(name); 194 } 195 196 void KeyframeEffectStack::addInvalidCSSAnimationName(const String& name) 197 { 198 m_invalidCSSAnimationNames.add(name); 199 } 200 201 bool KeyframeEffectStack::containsEffectThatPreventsAccelerationOfEffect(const KeyframeEffect& potentiallyAcceleratedEffect) 202 { 203 ensureEffectsAreSorted(); 204 205 for (auto& effect : m_effects) { 206 if (effect.get() == &potentiallyAcceleratedEffect) 207 continue; 208 if (effect->preventsAcceleration()) 209 return true; 210 } 211 212 return false; 232 effect->effectStackNoLongerPreventsAcceleration(); 233 } 234 235 void KeyframeEffectStack::stopAcceleratedAnimations() 236 { 237 for (auto& effect : m_effects) 238 effect->effectStackNoLongerAllowsAcceleration(); 213 239 } 214 240 -
trunk/Source/WebCore/animation/KeyframeEffectStack.h
r290730 r294391 58 58 bool hasEffectWithImplicitKeyframes() const; 59 59 60 bool containsEffectThatPreventsAccelerationOfEffect(const KeyframeEffect&); 61 62 void stopAcceleratingTransformRelatedProperties(UseAcceleratedAction); 60 void effectAbilityToBeAcceleratedDidChange(const KeyframeEffect&); 61 bool allowsAcceleration() const; 63 62 64 63 void clearInvalidCSSAnimationNames(); … … 70 69 void ensureEffectsAreSorted(); 71 70 71 void startAcceleratedAnimationsIfPossible(); 72 void stopAcceleratedAnimations(); 73 72 74 Vector<WeakPtr<KeyframeEffect>> m_effects; 73 75 HashSet<String> m_invalidCSSAnimationNames; -
trunk/Source/WebCore/animation/WebAnimationTypes.h
r271524 r294391 56 56 }; 57 57 58 enum class AcceleratedActionApplicationResult {59 TransformRelatedAnimationCannotBeAccelerated = 1 << 060 };61 62 58 enum class UseAcceleratedAction : uint8_t { Yes, No }; 63 59
Note:
See TracChangeset
for help on using the changeset viewer.