Diff
Modified: trunk/LayoutTests/ChangeLog (261925 => 261926)
--- trunk/LayoutTests/ChangeLog 2020-05-20 16:10:10 UTC (rev 261925)
+++ trunk/LayoutTests/ChangeLog 2020-05-20 16:26:16 UTC (rev 261926)
@@ -1,3 +1,24 @@
+2020-05-20 Antoine Quint <[email protected]>
+
+ [Web Animations] Animation engine should not wake up every tick for steps timing functions
+ https://bugs.webkit.org/show_bug.cgi?id=212103
+ <rdar://problem/62737868>
+
+ Reviewed by Simon Fraser.
+
+ Add tests that check that an animation using a steps() timing function correctly computes the time to
+ the next tick accouning for the fact that it won't compute a different iteration progress until the
+ next step.
+
+ * webanimations/scheduling-of-animation-with-steps-timing-function-on-effect-expected.txt: Added.
+ * webanimations/scheduling-of-animation-with-steps-timing-function-on-effect.html: Added.
+ * webanimations/scheduling-of-animation-with-steps-timing-function-on-keyframe-expected.txt: Added.
+ * webanimations/scheduling-of-animation-with-steps-timing-function-on-keyframe.html: Added.
+ * webanimations/scheduling-of-css-animation-with-explicit-steps-timing-function-on-some-keyframes-expected.txt: Added.
+ * webanimations/scheduling-of-css-animation-with-explicit-steps-timing-function-on-some-keyframes.html: Added.
+ * webanimations/scheduling-of-css-animation-with-implicit-steps-timing-function-expected.txt: Added.
+ * webanimations/scheduling-of-css-animation-with-implicit-steps-timing-function.html: Added.
+
2020-05-20 Noam Rosenthal <[email protected]>
Fix table sizing when 'max-width' is used
Added: trunk/LayoutTests/webanimations/scheduling-of-animation-with-steps-timing-function-on-effect-expected.txt (0 => 261926)
--- trunk/LayoutTests/webanimations/scheduling-of-animation-with-steps-timing-function-on-effect-expected.txt (rev 0)
+++ trunk/LayoutTests/webanimations/scheduling-of-animation-with-steps-timing-function-on-effect-expected.txt 2020-05-20 16:26:16 UTC (rev 261926)
@@ -0,0 +1,3 @@
+
+PASS Computing the time until the next tick for an effect with a steps() easing.
+
Added: trunk/LayoutTests/webanimations/scheduling-of-animation-with-steps-timing-function-on-effect.html (0 => 261926)
--- trunk/LayoutTests/webanimations/scheduling-of-animation-with-steps-timing-function-on-effect.html (rev 0)
+++ trunk/LayoutTests/webanimations/scheduling-of-animation-with-steps-timing-function-on-effect.html 2020-05-20 16:26:16 UTC (rev 261926)
@@ -0,0 +1,17 @@
+<script src=""
+<script src=""
+<div></div>
+<script>
+
+async_test(async t => {
+ const animation = document.querySelector("div").animate({ marginLeft: "100px" }, { duration: 1000, easing: "steps(10)" });
+
+ await animation.ready;
+
+ animation.currentTime = 225;
+ assert_equals(internals.timeToNextAnimationTick(animation), 75, "Computing the time until the next tick when partly through a steps interval.");
+
+ t.done();
+}, "Computing the time until the next tick for an effect with a steps() easing.");
+
+</script>
Added: trunk/LayoutTests/webanimations/scheduling-of-animation-with-steps-timing-function-on-keyframe-expected.txt (0 => 261926)
--- trunk/LayoutTests/webanimations/scheduling-of-animation-with-steps-timing-function-on-keyframe-expected.txt (rev 0)
+++ trunk/LayoutTests/webanimations/scheduling-of-animation-with-steps-timing-function-on-keyframe-expected.txt 2020-05-20 16:26:16 UTC (rev 261926)
@@ -0,0 +1,3 @@
+
+PASS Computing the time until the next tick for a keyframe with a steps() timing function.
+
Added: trunk/LayoutTests/webanimations/scheduling-of-animation-with-steps-timing-function-on-keyframe.html (0 => 261926)
--- trunk/LayoutTests/webanimations/scheduling-of-animation-with-steps-timing-function-on-keyframe.html (rev 0)
+++ trunk/LayoutTests/webanimations/scheduling-of-animation-with-steps-timing-function-on-keyframe.html 2020-05-20 16:26:16 UTC (rev 261926)
@@ -0,0 +1,20 @@
+<script src=""
+<script src=""
+<div></div>
+<script>
+
+async_test(async t => {
+ const animation = document.querySelector("div").animate({
+ marginLeft: ["0", "250px", "500px", "750px", "1000px"],
+ easing: ["linear", "linear", "steps(10)", "linear"]
+ }, 1000);
+
+ await animation.ready;
+
+ animation.currentTime = 535;
+ assert_equals(internals.timeToNextAnimationTick(animation), 15);
+
+ t.done();
+}, "Computing the time until the next tick for a keyframe with a steps() timing function.");
+
+</script>
Added: trunk/LayoutTests/webanimations/scheduling-of-css-animation-with-explicit-steps-timing-function-on-some-keyframes-expected.txt (0 => 261926)
--- trunk/LayoutTests/webanimations/scheduling-of-css-animation-with-explicit-steps-timing-function-on-some-keyframes-expected.txt (rev 0)
+++ trunk/LayoutTests/webanimations/scheduling-of-css-animation-with-explicit-steps-timing-function-on-some-keyframes-expected.txt 2020-05-20 16:26:16 UTC (rev 261926)
@@ -0,0 +1,3 @@
+
+PASS Computing the time until the next tick for a CSS Animation with implicit and explicit steps() timing functions.
+
Added: trunk/LayoutTests/webanimations/scheduling-of-css-animation-with-explicit-steps-timing-function-on-some-keyframes.html (0 => 261926)
--- trunk/LayoutTests/webanimations/scheduling-of-css-animation-with-explicit-steps-timing-function-on-some-keyframes.html (rev 0)
+++ trunk/LayoutTests/webanimations/scheduling-of-css-animation-with-explicit-steps-timing-function-on-some-keyframes.html 2020-05-20 16:26:16 UTC (rev 261926)
@@ -0,0 +1,39 @@
+<script src=""
+<script src=""
+<style>
+
+ div {
+ animation: anim 1s steps(10);
+ }
+
+ @keyframes anim {
+ 25% { margin-left: 250px }
+ 50% { margin-left: 500px; animation-timing-function: steps(5); }
+ 75% { margin-left: 750px }
+ }
+
+</style>
+<div></div>
+<script>
+
+async_test(async t => {
+ const animation = document.querySelector("div").getAnimations()[0];
+
+ await animation.ready;
+
+ animation.currentTime = 10;
+ assert_equals(internals.timeToNextAnimationTick(animation), 15, "Progress contained in the interval for an implicit 0% keyframe.");
+
+ animation.currentTime = 265;
+ assert_equals(internals.timeToNextAnimationTick(animation), 10, "Progress contained in the interval for an explicit keyframe with an implicit steps() timing-function.");
+
+ animation.currentTime = 510;
+ assert_equals(internals.timeToNextAnimationTick(animation), 40, "Progress contained in the interval for an explicit keyframe with an explicit steps() timing-function.");
+
+ animation.currentTime = 780;
+ assert_equals(internals.timeToNextAnimationTick(animation), 20, "Progress contained in the interval for an implicit 100% keyframe.");
+
+ t.done();
+}, "Computing the time until the next tick for a CSS Animation with implicit and explicit steps() timing functions.");
+
+</script>
Added: trunk/LayoutTests/webanimations/scheduling-of-css-animation-with-implicit-steps-timing-function-expected.txt (0 => 261926)
--- trunk/LayoutTests/webanimations/scheduling-of-css-animation-with-implicit-steps-timing-function-expected.txt (rev 0)
+++ trunk/LayoutTests/webanimations/scheduling-of-css-animation-with-implicit-steps-timing-function-expected.txt 2020-05-20 16:26:16 UTC (rev 261926)
@@ -0,0 +1,3 @@
+
+PASS Computing the time until the next tick for a CSS Animation with implicit steps() timing functions.
+
Added: trunk/LayoutTests/webanimations/scheduling-of-css-animation-with-implicit-steps-timing-function.html (0 => 261926)
--- trunk/LayoutTests/webanimations/scheduling-of-css-animation-with-implicit-steps-timing-function.html (rev 0)
+++ trunk/LayoutTests/webanimations/scheduling-of-css-animation-with-implicit-steps-timing-function.html 2020-05-20 16:26:16 UTC (rev 261926)
@@ -0,0 +1,31 @@
+<script src=""
+<script src=""
+<style>
+
+ div {
+ animation: anim 1s steps(10);
+ }
+
+ @keyframes anim {
+ 50% { margin-left: 500px; }
+ }
+
+</style>
+<div></div>
+<script>
+
+async_test(async t => {
+ const animation = document.querySelector("div").getAnimations()[0];
+
+ await animation.ready;
+
+ animation.currentTime = 10;
+ assert_equals(internals.timeToNextAnimationTick(animation), 40, "Progress contained in the interval for an implicit 0% keyframe.");
+
+ animation.currentTime = 920;
+ assert_equals(internals.timeToNextAnimationTick(animation), 30, "Progress contained in the interval for an implicit 100% keyframe.");
+
+ t.done();
+}, "Computing the time until the next tick for a CSS Animation with implicit steps() timing functions.");
+
+</script>
Modified: trunk/Source/WTF/ChangeLog (261925 => 261926)
--- trunk/Source/WTF/ChangeLog 2020-05-20 16:10:10 UTC (rev 261925)
+++ trunk/Source/WTF/ChangeLog 2020-05-20 16:26:16 UTC (rev 261926)
@@ -1,3 +1,17 @@
+2020-05-20 Antoine Quint <[email protected]>
+
+ [Web Animations] Animation engine should not wake up every tick for steps timing functions
+ https://bugs.webkit.org/show_bug.cgi?id=212103
+ <rdar://problem/62737868>
+
+ Reviewed by Simon Fraser.
+
+ Allow Seconds to be divided or multiplied by a double with operands in any order.
+
+ * wtf/Seconds.h:
+ (WTF::operator*):
+ (WTF::operator/):
+
2020-05-20 Youenn Fablet <[email protected]>
[Mac] Use preferedPixelBufferFormat for AVVideoCaptureSource
Modified: trunk/Source/WTF/wtf/Seconds.h (261925 => 261926)
--- trunk/Source/WTF/wtf/Seconds.h 2020-05-20 16:10:10 UTC (rev 261925)
+++ trunk/Source/WTF/wtf/Seconds.h 2020-05-20 16:26:16 UTC (rev 261926)
@@ -332,6 +332,16 @@
} // inline seconds_literals
+inline Seconds operator*(double scalar, Seconds seconds)
+{
+ return Seconds(scalar * seconds.value());
+}
+
+inline Seconds operator/(double scalar, Seconds seconds)
+{
+ return Seconds(scalar / seconds.value());
+}
+
WTF_EXPORT_PRIVATE TextStream& operator<<(TextStream&, Seconds);
} // namespace WTF
Modified: trunk/Source/WebCore/ChangeLog (261925 => 261926)
--- trunk/Source/WebCore/ChangeLog 2020-05-20 16:10:10 UTC (rev 261925)
+++ trunk/Source/WebCore/ChangeLog 2020-05-20 16:26:16 UTC (rev 261926)
@@ -1,3 +1,50 @@
+2020-05-20 Antoine Quint <[email protected]>
+
+ [Web Animations] Animation engine should not wake up every tick for steps timing functions
+ https://bugs.webkit.org/show_bug.cgi?id=212103
+ <rdar://problem/62737868>
+
+ Reviewed by Simon Fraser.
+
+ Tests: webanimations/scheduling-of-animation-with-steps-timing-function-on-effect.html
+ webanimations/scheduling-of-animation-with-steps-timing-function-on-keyframe.html
+ webanimations/scheduling-of-css-animation-with-explicit-steps-timing-function-on-some-keyframes.html
+ webanimations/scheduling-of-css-animation-with-implicit-steps-timing-function.html
+
+ When an animation uses a steps() timing function, it will appear to animate discretely between values such
+ that there is only n visual changes, where n is the number of steps provided. This gives us an opportunity
+ to be more efficient when scheduling animations using steps() timing functions.
+
+ In WebAnimation::timeToNextTick() we now ask the associated effect for the amount of progress until the next
+ step. For an effect-wide steps() timing function, we can use the provided iteration progress. For animations
+ with a linear effect-wide timing function (the default), we have to map the provided iteration progress to
+ a keyframe interval, provided that interval uses a steps() timing function.
+
+ The new {Animation|Keyframe}Effect::progressUntilNextStep() method returns WTF::nullopt for any other case.
+
+ In order to test this, we add a new internals.timeToNextAnimationTick(animation) method which we use in the
+ two new tests.
+
+ * animation/AnimationEffect.cpp:
+ (WebCore::AnimationEffect::progressUntilNextStep const):
+ * animation/AnimationEffect.h:
+ * animation/KeyframeEffect.cpp:
+ (WebCore::KeyframeEffect::setBlendingKeyframes):
+ (WebCore::KeyframeEffect::computeSomeKeyframesUseStepsTimingFunction):
+ (WebCore::KeyframeEffect::timingFunctionForKeyframeAtIndex const): Avoid any out-of-bounds use of the underlying data
+ structures by returning nullptr for cases where we don't have an explicit keyframe. We also make the function const
+ such that it may be called from progressUntilNextStep(), it always was const but wasn't marked as such.
+ (WebCore::KeyframeEffect::progressUntilNextStep const):
+ * animation/KeyframeEffect.h:
+ * animation/WebAnimation.cpp:
+ (WebCore::WebAnimation::timeToNextTick const):
+ * animation/WebAnimation.h:
+ * animation/WebAnimation.idl:
+ * testing/Internals.cpp:
+ (WebCore::Internals::timeToNextAnimationTick const):
+ * testing/Internals.h:
+ * testing/Internals.idl:
+
2020-05-20 Noam Rosenthal <[email protected]>
Fix table sizing when 'max-width' is used
Modified: trunk/Source/WebCore/animation/AnimationEffect.cpp (261925 => 261926)
--- trunk/Source/WebCore/animation/AnimationEffect.cpp 2020-05-20 16:10:10 UTC (rev 261925)
+++ trunk/Source/WebCore/animation/AnimationEffect.cpp 2020-05-20 16:26:16 UTC (rev 261926)
@@ -541,4 +541,14 @@
m_timingFunction = timingFunction;
}
+Optional<double> AnimationEffect::progressUntilNextStep(double iterationProgress) const
+{
+ if (!is<StepsTimingFunction>(m_timingFunction))
+ return WTF::nullopt;
+
+ auto numberOfSteps = downcast<StepsTimingFunction>(*m_timingFunction).numberOfSteps();
+ auto nextStepProgress = ceil(iterationProgress * numberOfSteps) / numberOfSteps;
+ return nextStepProgress - iterationProgress;
+}
+
} // namespace WebCore
Modified: trunk/Source/WebCore/animation/AnimationEffect.h (261925 => 261926)
--- trunk/Source/WebCore/animation/AnimationEffect.h 2020-05-20 16:10:10 UTC (rev 261925)
+++ trunk/Source/WebCore/animation/AnimationEffect.h 2020-05-20 16:26:16 UTC (rev 261926)
@@ -102,6 +102,8 @@
void updateStaticTimingProperties();
+ virtual Optional<double> progressUntilNextStep(double) const;
+
protected:
explicit AnimationEffect();
Modified: trunk/Source/WebCore/animation/AnimationTimeline.cpp (261925 => 261926)
--- trunk/Source/WebCore/animation/AnimationTimeline.cpp 2020-05-20 16:10:10 UTC (rev 261925)
+++ trunk/Source/WebCore/animation/AnimationTimeline.cpp 2020-05-20 16:26:16 UTC (rev 261926)
@@ -399,6 +399,9 @@
// If we already have a keyframe effect targeting this property, we should use its unanimated style to determine what the potential
// start value of the transition shoud be to make sure that we don't account for animated values that would have been blended onto
// the style applied during the last style resolution.
+
+ // FIXME: NO. We should be applying animations with the current time.
+
if (auto* unanimatedStyle = keyframeEffect->unanimatedStyle())
return RenderStyle::clone(*unanimatedStyle);
Modified: trunk/Source/WebCore/animation/KeyframeEffect.cpp (261925 => 261926)
--- trunk/Source/WebCore/animation/KeyframeEffect.cpp 2020-05-20 16:10:10 UTC (rev 261925)
+++ trunk/Source/WebCore/animation/KeyframeEffect.cpp 2020-05-20 16:26:16 UTC (rev 261926)
@@ -846,6 +846,7 @@
computedNeedsForcedLayout();
computeStackingContextImpact();
computeAcceleratedPropertiesState();
+ computeSomeKeyframesUseStepsTimingFunction();
checkForMatchingTransformFunctionLists();
checkForMatchingFilterFunctionLists();
@@ -1265,6 +1266,36 @@
m_acceleratedPropertiesState = AcceleratedProperties::All;
}
+void KeyframeEffect::computeSomeKeyframesUseStepsTimingFunction()
+{
+ m_someKeyframesUseStepsTimingFunction = false;
+
+ size_t numberOfKeyframes = m_blendingKeyframes.size();
+
+ // If we're dealing with a CSS Animation and it specifies a default steps() timing function,
+ // we need to check that any of the specified keyframes either does not have an explicit timing
+ // function or specifies an explicit steps() timing function.
+ if (is<CSSAnimation>(animation()) && is<StepsTimingFunction>(downcast<DeclarativeAnimation>(*animation()).backingAnimation().timingFunction())) {
+ for (size_t i = 0; i < numberOfKeyframes; i++) {
+ auto* timingFunction = m_blendingKeyframes[i].timingFunction();
+ if (!timingFunction || is<StepsTimingFunction>(timingFunction)) {
+ m_someKeyframesUseStepsTimingFunction = true;
+ return;
+ }
+ }
+ return;
+ }
+
+ // For any other type of animation, we just need to check whether any of the keyframes specify
+ // an explicit steps() timing function.
+ for (size_t i = 0; i < numberOfKeyframes; i++) {
+ if (is<StepsTimingFunction>(m_blendingKeyframes[i].timingFunction())) {
+ m_someKeyframesUseStepsTimingFunction = true;
+ return;
+ }
+ }
+}
+
void KeyframeEffect::getAnimatedStyle(std::unique_ptr<RenderStyle>& animatedStyle)
{
if (!renderer() || !animation())
@@ -1439,15 +1470,20 @@
}
}
-TimingFunction* KeyframeEffect::timingFunctionForKeyframeAtIndex(size_t index)
+TimingFunction* KeyframeEffect::timingFunctionForKeyframeAtIndex(size_t index) const
{
- if (!m_parsedKeyframes.isEmpty())
+ if (!m_parsedKeyframes.isEmpty()) {
+ if (index >= m_parsedKeyframes.size())
+ return nullptr;
return m_parsedKeyframes[index].timingFunction.get();
+ }
auto effectAnimation = animation();
if (is<DeclarativeAnimation>(effectAnimation)) {
// If we're dealing with a CSS Animation, the timing function is specified either on the keyframe itself.
if (is<CSSAnimation>(effectAnimation)) {
+ if (index >= m_blendingKeyframes.size())
+ return nullptr;
if (auto* timingFunction = m_blendingKeyframes[index].timingFunction())
return timingFunction;
}
@@ -1795,4 +1831,57 @@
return m_blendingKeyframesSource == BlendingKeyframesSource::WebAnimation && targetsPseudoElement();
}
+Optional<double> KeyframeEffect::progressUntilNextStep(double iterationProgress) const
+{
+ ASSERT(iterationProgress >= 0 && iterationProgress <= 1);
+
+ if (auto progress = AnimationEffect::progressUntilNextStep(iterationProgress))
+ return progress;
+
+ if (!is<LinearTimingFunction>(timingFunction()) || !m_someKeyframesUseStepsTimingFunction)
+ return WTF::nullopt;
+
+ if (m_blendingKeyframes.isEmpty())
+ return WTF::nullopt;
+
+ auto progressUntilNextStepInInterval = [iterationProgress](double intervalStartProgress, double intervalEndProgress, TimingFunction* timingFunction) -> Optional<double> {
+ if (!is<StepsTimingFunction>(timingFunction))
+ return WTF::nullopt;
+
+ auto numberOfSteps = downcast<StepsTimingFunction>(*timingFunction).numberOfSteps();
+ auto intervalProgress = intervalEndProgress - intervalStartProgress;
+ auto iterationProgressMappedToCurrentInterval = (iterationProgress - intervalStartProgress) / intervalProgress;
+ auto nextStepProgress = ceil(iterationProgressMappedToCurrentInterval * numberOfSteps) / numberOfSteps;
+ return (nextStepProgress - iterationProgressMappedToCurrentInterval) * intervalProgress;
+ };
+
+ for (size_t i = 0; i < m_blendingKeyframes.size(); ++i) {
+ auto intervalEndProgress = m_blendingKeyframes[i].key();
+ // We can stop once we find a keyframe for which the progress is more than the provided iteration progress.
+ if (intervalEndProgress <= iterationProgress)
+ continue;
+
+ // In case we're on the first keyframe, then this means we are dealing with an implicit 0% keyframe.
+ // This will be a linear timing function unless we're dealing with a CSS Animation which might have
+ // the default timing function for its keyframes defined on its backing Animation object.
+ if (!i) {
+ if (is<CSSAnimation>(animation()))
+ return progressUntilNextStepInInterval(0, intervalEndProgress, downcast<DeclarativeAnimation>(*animation()).backingAnimation().timingFunction());
+ return WTF::nullopt;
+ }
+
+ return progressUntilNextStepInInterval(m_blendingKeyframes[i - 1].key(), intervalEndProgress, timingFunctionForKeyframeAtIndex(i - 1));
+ }
+
+ // If we end up here, then this means we are dealing with an implicit 100% keyframe.
+ // This will be a linear timing function unless we're dealing with a CSS Animation which might have
+ // the default timing function for its keyframes defined on its backing Animation object.
+ auto& lastExplicitKeyframe = m_blendingKeyframes[m_blendingKeyframes.size() - 1];
+ if (is<CSSAnimation>(animation()))
+ return progressUntilNextStepInInterval(lastExplicitKeyframe.key(), 1, downcast<DeclarativeAnimation>(*animation()).backingAnimation().timingFunction());
+
+ // In any other case, we are not dealing with an interval with a steps() timing function.
+ return WTF::nullopt;
+}
+
} // namespace WebCore
Modified: trunk/Source/WebCore/animation/KeyframeEffect.h (261925 => 261926)
--- trunk/Source/WebCore/animation/KeyframeEffect.h 2020-05-20 16:10:10 UTC (rev 261925)
+++ trunk/Source/WebCore/animation/KeyframeEffect.h 2020-05-20 16:26:16 UTC (rev 261926)
@@ -181,10 +181,11 @@
void addPendingAcceleratedAction(AcceleratedAction);
void updateAcceleratedActions();
void setAnimatedPropertiesInStyle(RenderStyle&, double);
- TimingFunction* timingFunctionForKeyframeAtIndex(size_t);
+ TimingFunction* timingFunctionForKeyframeAtIndex(size_t) const;
Ref<const Animation> backingAnimationForCompositedRenderer() const;
void computedNeedsForcedLayout();
void computeStackingContextImpact();
+ void computeSomeKeyframesUseStepsTimingFunction();
void clearBlendingKeyframes();
void updateBlendingKeyframes(RenderStyle&);
void computeCSSAnimationBlendingKeyframes(const RenderStyle&);
@@ -191,6 +192,7 @@
void computeCSSTransitionBlendingKeyframes(const RenderStyle* oldStyle, const RenderStyle& newStyle);
void computeAcceleratedPropertiesState();
void setBlendingKeyframes(KeyframeList&);
+ Optional<double> progressUntilNextStep(double) const final;
void checkForMatchingTransformFunctionLists();
void checkForMatchingFilterFunctionLists();
void checkForMatchingColorFilterFunctionLists();
@@ -222,6 +224,7 @@
#endif
bool m_colorFilterFunctionListsMatch { false };
bool m_inTargetEffectStack { false };
+ bool m_someKeyframesUseStepsTimingFunction { false };
};
} // namespace WebCore
Modified: trunk/Source/WebCore/animation/WebAnimation.cpp (261925 => 261926)
--- trunk/Source/WebCore/animation/WebAnimation.cpp 2020-05-20 16:10:10 UTC (rev 261925)
+++ trunk/Source/WebCore/animation/WebAnimation.cpp 2020-05-20 16:26:16 UTC (rev 261926)
@@ -1482,6 +1482,11 @@
// Fully-accelerated running animations in the "active" phase can wait until they ended.
return (effect.endTime() - timing.localTime.value()) / playbackRate;
}
+ if (auto iterationProgress = effect.getComputedTiming().simpleIterationProgress) {
+ // In case we're in a range that uses a steps() timing function, we can compute the time until the next step starts.
+ if (auto progressUntilNextStep = effect.progressUntilNextStep(*iterationProgress))
+ return effect.iterationDuration() * *progressUntilNextStep / playbackRate;
+ }
// Other animations in the "active" phase will need to update their animated value at the immediate next opportunity.
return 0_s;
case AnimationEffectPhase::After:
Modified: trunk/Source/WebCore/animation/WebAnimation.h (261925 => 261926)
--- trunk/Source/WebCore/animation/WebAnimation.h 2020-05-20 16:10:10 UTC (rev 261925)
+++ trunk/Source/WebCore/animation/WebAnimation.h 2020-05-20 16:26:16 UTC (rev 261926)
@@ -120,7 +120,7 @@
bool needsTick() const;
virtual void tick();
- Seconds timeToNextTick() const;
+ WEBCORE_EXPORT Seconds timeToNextTick() const;
virtual void resolve(RenderStyle&);
void effectTargetDidChange(Element* previousTarget, Element* newTarget);
void acceleratedStateDidChange();
Modified: trunk/Source/WebCore/animation/WebAnimation.idl (261925 => 261926)
--- trunk/Source/WebCore/animation/WebAnimation.idl 2020-05-20 16:10:10 UTC (rev 261925)
+++ trunk/Source/WebCore/animation/WebAnimation.idl 2020-05-20 16:26:16 UTC (rev 261926)
@@ -41,7 +41,8 @@
EnabledAtRuntime=WebAnimations,
InterfaceName=Animation,
CustomConstructor(),
- CustomToJSObject
+ CustomToJSObject,
+ ExportMacro=WEBCORE_EXPORT
] interface WebAnimation : EventTarget {
attribute DOMString id;
[ImplementedAs=bindingsEffect] attribute AnimationEffect? effect;
Modified: trunk/Source/WebCore/style/StyleTreeResolver.cpp (261925 => 261926)
--- trunk/Source/WebCore/style/StyleTreeResolver.cpp 2020-05-20 16:10:10 UTC (rev 261925)
+++ trunk/Source/WebCore/style/StyleTreeResolver.cpp 2020-05-20 16:26:16 UTC (rev 261926)
@@ -317,6 +317,7 @@
if (oldStyle && (oldStyle->hasTransitions() || newStyle->hasTransitions()))
m_document.timeline().updateCSSTransitionsForElement(element, *oldStyle, *newStyle);
+ // FIXME: Maybe need to do this first such that CSS Transitions are aware of newly created or canceled animations
if ((oldStyle && oldStyle->hasAnimations()) || newStyle->hasAnimations())
m_document.timeline().updateCSSAnimationsForElement(element, oldStyle, *newStyle);
}
Modified: trunk/Source/WebCore/testing/Internals.cpp (261925 => 261926)
--- trunk/Source/WebCore/testing/Internals.cpp 2020-05-20 16:10:10 UTC (rev 261925)
+++ trunk/Source/WebCore/testing/Internals.cpp 2020-05-20 16:26:16 UTC (rev 261926)
@@ -196,6 +196,7 @@
#include "ViewportArguments.h"
#include "VoidCallback.h"
#include "WebAnimation.h"
+#include "WebAnimationUtilities.h"
#include "WebCoreJSClientData.h"
#include "WindowProxy.h"
#include "WorkerThread.h"
@@ -1200,6 +1201,11 @@
return 0;
}
+double Internals::timeToNextAnimationTick(WebAnimation& animation) const
+{
+ return secondsToWebAnimationsAPITime(animation.timeToNextTick());
+}
+
ExceptionOr<RefPtr<Element>> Internals::pseudoElement(Element& element, const String& pseudoId)
{
if (pseudoId != "before" && pseudoId != "after")
Modified: trunk/Source/WebCore/testing/Internals.h (261925 => 261926)
--- trunk/Source/WebCore/testing/Internals.h 2020-05-20 16:10:10 UTC (rev 261925)
+++ trunk/Source/WebCore/testing/Internals.h 2020-05-20 16:26:16 UTC (rev 261926)
@@ -106,6 +106,7 @@
class TypeConversions;
class UnsuspendableActiveDOMObject;
class VoidCallback;
+class WebAnimation;
class WebGLRenderingContext;
class WindowProxy;
class XMLHttpRequest;
@@ -239,6 +240,7 @@
};
Vector<AcceleratedAnimation> acceleratedAnimationsForElement(Element&);
unsigned numberOfAnimationTimelineInvalidations() const;
+ double timeToNextAnimationTick(WebAnimation&) const;
// For animations testing, we need a way to get at pseudo elements.
ExceptionOr<RefPtr<Element>> pseudoElement(Element&, const String&);
Modified: trunk/Source/WebCore/testing/Internals.idl (261925 => 261926)
--- trunk/Source/WebCore/testing/Internals.idl 2020-05-20 16:10:10 UTC (rev 261925)
+++ trunk/Source/WebCore/testing/Internals.idl 2020-05-20 16:26:16 UTC (rev 261926)
@@ -297,6 +297,7 @@
// Web Animations testing.
sequence<AcceleratedAnimation> acceleratedAnimationsForElement(Element element);
unsigned long numberOfAnimationTimelineInvalidations();
+ double timeToNextAnimationTick(WebAnimation animation);
// For animations testing, we need a way to get at pseudo elements.
[MayThrowException] Element? pseudoElement(Element element, DOMString pseudoId);