Skip to content

Commit

Permalink
Cherry-pick 275168@main (9f21b9e). https://bugs.webkit.org/show_bug.c…
Browse files Browse the repository at this point in the history
…gi?id=269288

    [Nicosia] Add support for translate/rotate/scale animations
    https://bugs.webkit.org/show_bug.cgi?id=269288

    Reviewed by Nikolas Zimmermann.

    Nicosia already supports accelerated transform animations.
    This patch implements translate, rotate, and scale animations.

    It also ensures that when multiple animations are applied,
    they run in the correct order required the spec [1]:
    - translate
    - rotate
    - scale
    - transform

    [1] https://drafts.csswg.org/css-transforms-2/#ctm

    * LayoutTests/platform/glib/TestExpectations:
    * LayoutTests/platform/wpe/TestExpectations:
    * Source/WebCore/platform/graphics/nicosia/NicosiaAnimation.cpp:
    (Nicosia::Animation::apply):
    (Nicosia::Animation::applyInternal):
    (Nicosia::Animations::apply):
    (Nicosia::Animations::hasRunningTransformAnimations const):
    (Nicosia::Animation::applyKeepingInternalState): Deleted.
    (Nicosia::Animations::applyKeepingInternalState): Deleted.
    * Source/WebCore/platform/graphics/nicosia/NicosiaAnimation.h:
    (Nicosia::Animations::setTranslate):
    (Nicosia::Animations::setRotate):
    (Nicosia::Animations::setScale):
    (Nicosia::Animations::setTransform):
    * Source/WebCore/platform/graphics/texmap/TextureMapperLayer.cpp:
    (WebCore::TextureMapperLayer::syncAnimations):
    * Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedGraphicsLayer.cpp:
    (WebCore::CoordinatedGraphicsLayer::didChangeAnimations):
    (WebCore::CoordinatedGraphicsLayer::addAnimation):
    (WebCore::CoordinatedGraphicsLayer::transformRelatedPropertyDidChange):
    * Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedGraphicsLayer.h:

    Canonical link: https://commits.webkit.org/275168@main
  • Loading branch information
obyknovenius authored and aperezdc committed Feb 22, 2024
1 parent 186dcff commit 83c85d3
Show file tree
Hide file tree
Showing 7 changed files with 138 additions and 32 deletions.
1 change: 0 additions & 1 deletion LayoutTests/platform/glib/TestExpectations
Original file line number Diff line number Diff line change
Expand Up @@ -1756,7 +1756,6 @@ webkit.org/b/132995 transitions/cancel-transition.html [ Failure Pass ]

webkit.org/b/211948 webanimations/accelerated-animation-playback-rate.html [ ImageOnlyFailure ]
webkit.org/b/212020 webanimations/accelerated-animation-single-keyframe.html [ Skip ]
webkit.org/b/213783 webanimations/accelerated-animation-with-easing.html [ ImageOnlyFailure ]

webkit.org/b/215945 webanimations/accelerated-css-animation-with-easing.html [ ImageOnlyFailure ]

Expand Down
1 change: 0 additions & 1 deletion LayoutTests/platform/wpe/TestExpectations
Original file line number Diff line number Diff line change
Expand Up @@ -1587,7 +1587,6 @@ webkit.org/b/264680 svg/css/svg-resource-fragment-identifier-img-src.html [ Imag
webkit.org/b/264680 tables/mozilla_expected_failures/bugs/bug2479-5.html [ Failure Missing Pass ]

fast/history/page-cache-execute-script-during-restore.html [ Timeout ]
webanimations/animation-page-cache.html [ Timeout ]

imported/w3c/web-platform-tests/css/css-masking/clip-path-svg-content/mask-and-nested-clip-path.svg [ Failure ]
imported/w3c/web-platform-tests/css/css-masking/clip-path-svg-content/mask-nested-clip-path-006.svg [ Failure ]
Expand Down
129 changes: 105 additions & 24 deletions Source/WebCore/platform/graphics/nicosia/NicosiaAnimation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

#include "LayoutSize.h"
#include "TranslateTransformOperation.h"
#include <wtf/Scope.h>

namespace Nicosia {

Expand Down Expand Up @@ -217,8 +218,20 @@ Animation& Animation::operator=(const Animation& other)
return *this;
}

void Animation::apply(ApplicationResult& applicationResults, MonotonicTime time)
void Animation::apply(ApplicationResult& applicationResults, MonotonicTime time, KeepInternalState keepInternalState)
{
MonotonicTime oldLastRefreshedTime = m_lastRefreshedTime;
Seconds oldTotalRunningTime = m_totalRunningTime;
AnimationState oldState = m_state;

auto maybeRestoreInternalState = makeScopeExit([&] {
if (keepInternalState == KeepInternalState::Yes) {
m_lastRefreshedTime = oldLastRefreshedTime;
m_totalRunningTime = oldTotalRunningTime;
m_state = oldState;
}
});

// Even when m_state == AnimationState::Stopped && !m_fillsForwards, we should calculate the last value to avoid a flash.
// CoordinatedGraphicsScene will soon remove the stopped animation and update the value instead of this function.

Expand Down Expand Up @@ -263,19 +276,6 @@ void Animation::apply(ApplicationResult& applicationResults, MonotonicTime time)
}
}

void Animation::applyKeepingInternalState(ApplicationResult& applicationResults, MonotonicTime time)
{
MonotonicTime oldLastRefreshedTime = m_lastRefreshedTime;
Seconds oldTotalRunningTime = m_totalRunningTime;
AnimationState oldState = m_state;

apply(applicationResults, time);

m_lastRefreshedTime = oldLastRefreshedTime;
m_totalRunningTime = oldTotalRunningTime;
m_state = oldState;
}

void Animation::pause(Seconds time)
{
m_state = AnimationState::Paused;
Expand Down Expand Up @@ -306,9 +306,15 @@ Seconds Animation::computeTotalRunningTime(MonotonicTime time)
void Animation::applyInternal(ApplicationResult& applicationResults, const AnimationValue& from, const AnimationValue& to, float progress)
{
switch (m_keyframes.property()) {
case AnimatedProperty::Transform:
applicationResults.transform = applyTransformAnimation(static_cast<const TransformAnimationValue&>(from).value(), static_cast<const TransformAnimationValue&>(to).value(), progress, m_boxSize);
case AnimatedProperty::Translate:
case AnimatedProperty::Rotate:
case AnimatedProperty::Scale:
case AnimatedProperty::Transform: {
ASSERT(applicationResults.transform);
auto transform = applyTransformAnimation(static_cast<const TransformAnimationValue&>(from).value(), static_cast<const TransformAnimationValue&>(to).value(), progress, m_boxSize);
applicationResults.transform->multiply(transform);
return;
}
case AnimatedProperty::Opacity:
applicationResults.opacity = applyOpacityAnimation((static_cast<const FloatAnimationValue&>(from).value()), (static_cast<const FloatAnimationValue&>(to).value()), progress);
return;
Expand Down Expand Up @@ -365,16 +371,65 @@ void Animations::resume()
animation.resume();
}

void Animations::apply(Animation::ApplicationResult& applicationResults, MonotonicTime time)
void Animations::apply(Animation::ApplicationResult& applicationResults, MonotonicTime time, Animation::KeepInternalState keepInternalState)
{
for (auto& animation : m_animations)
animation.apply(applicationResults, time);
}
Vector<Animation*> translateAnimations;
Vector<Animation*> rotateAnimations;
Vector<Animation*> scaleAnimations;
Vector<Animation*> transformAnimations;
Vector<Animation*> leafAnimations;

void Animations::applyKeepingInternalState(Animation::ApplicationResult& applicationResults, MonotonicTime time)
{
for (auto& animation : m_animations)
animation.applyKeepingInternalState(applicationResults, time);
for (auto& animation : m_animations) {
switch (animation.keyframes().property()) {
case AnimatedProperty::Translate:
translateAnimations.append(&animation);
break;
case AnimatedProperty::Rotate:
rotateAnimations.append(&animation);
break;
case AnimatedProperty::Scale:
scaleAnimations.append(&animation);
break;
case AnimatedProperty::Transform:
transformAnimations.append(&animation);
break;
default:
leafAnimations.append(&animation);
}
}

if (!translateAnimations.isEmpty() || !rotateAnimations.isEmpty() || !scaleAnimations.isEmpty() || !transformAnimations.isEmpty()) {
applicationResults.transform = TransformationMatrix();

if (translateAnimations.isEmpty())
applicationResults.transform->multiply(m_translate);
else {
for (auto* animation : translateAnimations)
animation->apply(applicationResults, time, keepInternalState);
}

if (rotateAnimations.isEmpty())
applicationResults.transform->multiply(m_rotate);
else {
for (auto* animation : rotateAnimations)
animation->apply(applicationResults, time, keepInternalState);
}

if (scaleAnimations.isEmpty())
applicationResults.transform->multiply(m_scale);
else {
for (auto* animation : scaleAnimations)
animation->apply(applicationResults, time, keepInternalState);
}

if (transformAnimations.isEmpty())
applicationResults.transform->multiply(m_transform);
else
transformAnimations.last()->apply(applicationResults, time, keepInternalState);
}

for (auto* animation : leafAnimations)
animation->apply(applicationResults, time, keepInternalState);
}

bool Animations::hasActiveAnimationsOfType(AnimatedProperty type) const
Expand All @@ -393,4 +448,30 @@ bool Animations::hasRunningAnimations() const
});
}

bool Animations::hasRunningTransformAnimations() const
{
return std::any_of(m_animations.begin(), m_animations.end(),
[](const Animation& animation) {
switch (animation.keyframes().property()) {
case AnimatedProperty::Translate:
case AnimatedProperty::Rotate:
case AnimatedProperty::Scale:
case AnimatedProperty::Transform:
break;
default:
return false;
}

switch (animation.state()) {
case Animation::AnimationState::Playing:
case Animation::AnimationState::Paused:
break;
default:
return false;
}

return true;
});
}

} // namespace Nicosia
22 changes: 17 additions & 5 deletions Source/WebCore/platform/graphics/nicosia/NicosiaAnimation.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,9 @@ class Animation {
Animation(Animation&&) = default;
Animation& operator=(Animation&&) = default;

void apply(ApplicationResult&, MonotonicTime);
void applyKeepingInternalState(ApplicationResult&, MonotonicTime);
enum class KeepInternalState { Yes, No };
void apply(ApplicationResult&, MonotonicTime, KeepInternalState);

void pause(Seconds);
void resume();

Expand Down Expand Up @@ -82,25 +83,36 @@ class Animations {
public:
Animations() = default;

void setTranslate(WebCore::TransformationMatrix transform) { m_translate = transform; }
void setRotate(WebCore::TransformationMatrix transform) { m_rotate = transform; }
void setScale(WebCore::TransformationMatrix transform) { m_scale = transform; }
void setTransform(WebCore::TransformationMatrix transform) { m_transform = transform; }

void add(const Animation&);
void remove(const String& name);
void remove(const String& name, WebCore::AnimatedProperty);
void pause(const String&, Seconds);
void suspend(MonotonicTime);
void resume();

void apply(Animation::ApplicationResult&, MonotonicTime);
void applyKeepingInternalState(Animation::ApplicationResult&, MonotonicTime);
void apply(Animation::ApplicationResult&, MonotonicTime, Animation::KeepInternalState = Animation::KeepInternalState::No);

bool isEmpty() const { return m_animations.isEmpty(); }
size_t size() const { return m_animations.size(); }
const Vector<Animation>& animations() const { return m_animations; }
Vector<Animation>& animations() { return m_animations; }

bool hasRunningAnimations() const;
bool hasActiveAnimationsOfType(WebCore::AnimatedProperty type) const;

bool hasRunningAnimations() const;
bool hasRunningTransformAnimations() const;

private:
WebCore::TransformationMatrix m_translate;
WebCore::TransformationMatrix m_rotate;
WebCore::TransformationMatrix m_scale;
WebCore::TransformationMatrix m_transform;

Vector<Animation> m_animations;
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1043,7 +1043,7 @@ bool TextureMapperLayer::syncAnimations(MonotonicTime time)
#if USE(COORDINATED_GRAPHICS)
// Calculate localTransform 50ms in the future.
Nicosia::Animation::ApplicationResult futureApplicationResults;
m_animations.applyKeepingInternalState(futureApplicationResults, time + 50_ms);
m_animations.apply(futureApplicationResults, time + 50_ms, Nicosia::Animation::KeepInternalState::Yes);
m_layerTransforms.futureLocalTransform = futureApplicationResults.transform.value_or(m_layerTransforms.localTransform);
#endif

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,11 @@ void CoordinatedGraphicsLayer::notifyFlushRequired()

void CoordinatedGraphicsLayer::didChangeAnimations()
{
m_animations.setTranslate(client().transformMatrixForProperty(AnimatedProperty::Translate));
m_animations.setRotate(client().transformMatrixForProperty(AnimatedProperty::Rotate));
m_animations.setScale(client().transformMatrixForProperty(AnimatedProperty::Scale));
m_animations.setTransform(client().transformMatrixForProperty(AnimatedProperty::Transform));

m_nicosia.delta.animationsChanged = true;
notifyFlushRequired();
}
Expand Down Expand Up @@ -1425,6 +1430,9 @@ bool CoordinatedGraphicsLayer::addAnimation(const KeyframeValueList& valueList,
break;
}
case AnimatedProperty::Opacity:
case AnimatedProperty::Translate:
case AnimatedProperty::Rotate:
case AnimatedProperty::Scale:
case AnimatedProperty::Transform:
break;
default:
Expand Down Expand Up @@ -1462,6 +1470,12 @@ void CoordinatedGraphicsLayer::resumeAnimations()
didChangeAnimations();
}

void CoordinatedGraphicsLayer::transformRelatedPropertyDidChange()
{
if (m_animations.hasRunningTransformAnimations())
didChangeAnimations();
}

void CoordinatedGraphicsLayer::animationStartedTimerFired()
{
client().notifyAnimationStarted(this, emptyString(), m_lastAnimationStartTime);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ class WEBCORE_EXPORT CoordinatedGraphicsLayer : public GraphicsLayer {
void removeAnimation(const String&, std::optional<AnimatedProperty>) override;
void suspendAnimations(MonotonicTime) override;
void resumeAnimations() override;
void transformRelatedPropertyDidChange() override;
bool usesContentsLayer() const override;
void dumpAdditionalProperties(WTF::TextStream&, OptionSet<LayerTreeAsTextOptions>) const override;

Expand Down

0 comments on commit 83c85d3

Please sign in to comment.