Changeset 268615 in webkit


Ignore:
Timestamp:
Oct 16, 2020 3:43:54 PM (4 years ago)
Author:
graouts@webkit.org
Message:

Support accelerated animation of individual transform CSS properties
https://bugs.webkit.org/show_bug.cgi?id=217842
<rdar://problem/70391914>

Reviewed by Dean Jackson.

LayoutTests/imported/w3c:

  • web-platform-tests/css/css-transforms/animation/rotate-interpolation-expected.txt:
  • web-platform-tests/css/css-transforms/animation/scale-interpolation-expected.txt:
  • web-platform-tests/css/css-transforms/animation/translate-interpolation-expected.txt:

Source/WebCore:

In order to support accelerated animation of individual transform CSS properties, we make a list of the
various animations targeting animation-related properties in GraphicsLayerCA::updateAnimations() and apply
an animation for each of those properties in their expected application order – translate, scale, rotate and
then transform – using Core Animation's additive animation mode.

When one of those properties does not have an animation, we create a non-interpolating base transform value
animation set with both from and to values matching the value set in CSS for this particular property. We use
a new transformMatrixForProperty() method on the GraphicsLayerClient to obtain this value.

We also add a non-additive, non-interpolating identity transform first to make sure all the additive animations
build on top of a neutral transform and not the underlying value applied to the layer.

Finally, when GraphicsLayerCA::setTransform() is updated, we update the animations to ensure that any base
transform value animation is updated to match the current value of the CSS properties contributing to the
compound layer transform.

Tests: webanimations/accelerated-transform-related-animation-property-order.html

webanimations/accelerated-translate-animation-additional-animation-added-in-flight.html
webanimations/accelerated-translate-animation-underlying-transform-changed-in-flight.html
webanimations/accelerated-translate-animation-with-transform.html
webanimations/accelerated-translate-animation.html

  • animation/CSSPropertyAnimation.cpp: Add the necessary animationIsAccelerated() overrides for each of the

individual CSS transform property animation wrappers to indicate that accelerated animations are supported.

  • platform/graphics/GraphicsLayer.cpp:

(WebCore::GraphicsLayer::validateTransformOperations): Update the ASSERT to check that the animated property
is any of the transform-related properties.

  • platform/graphics/GraphicsLayer.h:

(WebCore::TransformAnimationValue::TransformAnimationValue): Add a new constructor that takes a single TransformOperation*
value as input instead of a TransformOperations& so that the values coming from the individual CSS transform properties
can be used to create a TransformAnimationValue in RenderLayerBacking::startAnimation().

  • platform/graphics/GraphicsLayerClient.h: Add the new animated property identifiers for the individual CSS transform properties.

(WebCore::animatedPropertyIsTransformOrRelated): Add a new utility to identify any of the transform-related animated property
identifiers.
(WebCore::GraphicsLayerClient::transformMatrixForProperty const): New method called from GraphicsLayerCA::updateAnimations()
to query the client, such as RenderLayerBacking, for the TransformationMatrix representing a given CSS property value to be
used for base transform value non-interpolating animations.

  • platform/graphics/ca/GraphicsLayerCA.cpp:

(WebCore::propertyIdToString): Account for the new animated property identifiers.
(WebCore::GraphicsLayerCA::setTransform): If we are currently running a transform-related animation, a change in underlying
transform value means we must re-evaluate all transform-related animations to ensure that the base value transform animations
are current.
(WebCore::GraphicsLayerCA::moveOrCopyAnimations):
(WebCore::GraphicsLayerCA::addAnimation):
(WebCore::GraphicsLayerCA::updateAnimations): When updating animations, keep track of the most recent animation applicable to each
individual CSS transform property and the list of animations targeting the transform CSS property. Then, ensure those animations
are applied in the specified order – translate, scale, rotate and transform – by adding those animations as additive CA animations
with non-interpolating base transform value animations for each property that does not have a specified interpolating animation.
(WebCore::GraphicsLayerCA::isRunningTransformAnimation const): Ensure we also consider paused animations as "running" animations.
(WebCore::GraphicsLayerCA::appendToUncommittedAnimations): Whether a transform animation needs to be run using the additive mode
is now determined in updateAnimations() so we remove all code related to working out whether animations ought to be additive.
(WebCore::GraphicsLayerCA::createTransformAnimationsFromKeyframes): We force the creation of CATransform3D values for individual
CSS transform properties since only this mode guarantees that additivity of such animations will yield the expected result where
the transforms are multiplied rather than simply adding float values of individual components.

  • platform/graphics/ca/GraphicsLayerCA.h:
  • rendering/RenderLayerBacking.cpp:

(WebCore::RenderLayerBacking::startAnimation): Ensure we start animations for the individual CSS transform properties.
(WebCore::RenderLayerBacking::graphicsLayerToCSSProperty):
(WebCore::RenderLayerBacking::cssToGraphicsLayerProperty):
(WebCore::RenderLayerBacking::transformMatrixForProperty const): Implement the new GraphicsLayerClient method to provide a
matrix that can be used as a value for non-interpolating base value transform animations in GraphicsLayerCA::updateAnimations()
for any of the transform-related CSS properties.

  • rendering/RenderLayerBacking.h:
  • rendering/RenderLayerCompositor.cpp:

(WebCore::RenderLayerCompositor::requiresCompositingForAnimation const): Ensure that an animation for any of the transform-related
CSS properties yields composition of the target layer.
(WebCore::RenderLayerCompositor::isRunningTransformAnimation const):

  • rendering/style/WillChangeData.cpp:

(WebCore::propertyTriggersCompositingOnBoxesOnly): Ensure that setting the will-change CSS property to any of the transform-related
CSS properties yields composition of the target.

LayoutTests:

Add some new tests that check animations of individual CSS transform properties can be performed,
checking on their relative order with the transform property, updating the transform property while
an animation is in flight and adding animations while in flight.

  • TestExpectations:
  • webanimations/accelerated-transform-related-animation-property-order-expected.html: Added.
  • webanimations/accelerated-transform-related-animation-property-order.html: Added.
  • webanimations/accelerated-translate-animation-additional-animation-added-in-flight-expected.html: Added.
  • webanimations/accelerated-translate-animation-additional-animation-added-in-flight.html: Added.
  • webanimations/accelerated-translate-animation-expected.html: Added.
  • webanimations/accelerated-translate-animation-underlying-transform-changed-in-flight-expected.html: Added.
  • webanimations/accelerated-translate-animation-underlying-transform-changed-in-flight.html: Added.
  • webanimations/accelerated-translate-animation-with-transform-expected.html: Added.
  • webanimations/accelerated-translate-animation-with-transform.html: Added.
  • webanimations/accelerated-translate-animation.html: Added.
Location:
trunk
Files:
10 added
17 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r268614 r268615  
     12020-10-16  Antoine Quint  <graouts@webkit.org>
     2
     3        Support accelerated animation of individual transform CSS properties
     4        https://bugs.webkit.org/show_bug.cgi?id=217842
     5        <rdar://problem/70391914>
     6
     7        Reviewed by Dean Jackson.
     8
     9        Add some new tests that check animations of individual CSS transform properties can be performed,
     10        checking on their relative order with the transform property, updating the transform property while
     11        an animation is in flight and adding animations while in flight.
     12
     13        * TestExpectations:
     14        * webanimations/accelerated-transform-related-animation-property-order-expected.html: Added.
     15        * webanimations/accelerated-transform-related-animation-property-order.html: Added.
     16        * webanimations/accelerated-translate-animation-additional-animation-added-in-flight-expected.html: Added.
     17        * webanimations/accelerated-translate-animation-additional-animation-added-in-flight.html: Added.
     18        * webanimations/accelerated-translate-animation-expected.html: Added.
     19        * webanimations/accelerated-translate-animation-underlying-transform-changed-in-flight-expected.html: Added.
     20        * webanimations/accelerated-translate-animation-underlying-transform-changed-in-flight.html: Added.
     21        * webanimations/accelerated-translate-animation-with-transform-expected.html: Added.
     22        * webanimations/accelerated-translate-animation-with-transform.html: Added.
     23        * webanimations/accelerated-translate-animation.html: Added.
     24
    1252020-10-16  Karl Rackler  <rackler@apple.com>
    226
  • trunk/LayoutTests/TestExpectations

    r268488 r268615  
    45204520webkit.org/b/217054 fast/layoutformattingcontext/horizontal-sizing-with-trailing-letter-spacing.html [ Skip ]
    45214521
     4522webkit.org/b/217851 transitions/interrupted-transition-hardware.html [ Pass Failure ]
     4523webkit.org/b/217851 webanimations/accelerated-transform-related-animation-property-order.html [ Pass Failure ]
     4524webkit.org/b/217851 webanimations/accelerated-translate-animation-additional-animation-added-in-flight.html [ Pass Failure ]
     4525webkit.org/b/217851 webanimations/accelerated-translate-animation-underlying-transform-changed-in-flight.html [ Pass Failure ]
     4526webkit.org/b/217851 webanimations/accelerated-translate-animation-with-transform.html [ Pass Failure ]
     4527webkit.org/b/217851 webanimations/accelerated-translate-animation.html [ Pass Failure ]
  • trunk/LayoutTests/imported/w3c/ChangeLog

    r268564 r268615  
     12020-10-16  Antoine Quint  <graouts@webkit.org>
     2
     3        Support accelerated animation of individual transform CSS properties
     4        https://bugs.webkit.org/show_bug.cgi?id=217842
     5        <rdar://problem/70391914>
     6
     7        Reviewed by Dean Jackson.
     8
     9        * web-platform-tests/css/css-transforms/animation/rotate-interpolation-expected.txt:
     10        * web-platform-tests/css/css-transforms/animation/scale-interpolation-expected.txt:
     11        * web-platform-tests/css/css-transforms/animation/translate-interpolation-expected.txt:
     12
    1132020-10-15  Sam Weinig  <weinig@apple.com>
    214
  • trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-transforms/animation/rotate-interpolation-expected.txt

    r268173 r268615  
    138138PASS CSS Animations: property <rotate> from neutral to [30deg] at (1) should be [30deg]
    139139PASS CSS Animations: property <rotate> from neutral to [30deg] at (2) should be [50deg]
    140 PASS Web Animations: property <rotate> from neutral to [30deg] at (-1) should be [-10deg]
     140FAIL Web Animations: property <rotate> from neutral to [30deg] at (-1) should be [-10deg] assert_equals: expected "- 10deg " but got "- 50deg "
    141141FAIL Web Animations: property <rotate> from neutral to [30deg] at (0) should be [10deg] assert_equals: expected "10deg " but got "- 10deg "
    142 FAIL Web Animations: property <rotate> from neutral to [30deg] at (0.25) should be [15deg] assert_equals: expected "15deg " but got "none "
    143 FAIL Web Animations: property <rotate> from neutral to [30deg] at (0.75) should be [25deg] assert_equals: expected "25deg " but got "22.5deg "
     142FAIL Web Animations: property <rotate> from neutral to [30deg] at (0.25) should be [15deg] assert_equals: expected "15deg " but got "7.5deg "
     143FAIL Web Animations: property <rotate> from neutral to [30deg] at (0.75) should be [25deg] assert_equals: expected "25deg " but got "28.13deg "
    144144PASS Web Animations: property <rotate> from neutral to [30deg] at (1) should be [30deg]
    145145FAIL Web Animations: property <rotate> from neutral to [30deg] at (2) should be [50deg] assert_equals: expected "50deg " but got "30deg "
  • trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-transforms/animation/scale-interpolation-expected.txt

    r268173 r268615  
    186186PASS CSS Animations: property <scale> from neutral to [1.5 1] at (1) should be [1.5 1]
    187187PASS CSS Animations: property <scale> from neutral to [1.5 1] at (2) should be [1.9 1]
    188 PASS Web Animations: property <scale> from neutral to [1.5 1] at (-1) should be [0.7 1]
     188FAIL Web Animations: property <scale> from neutral to [1.5 1] at (-1) should be [0.7 1] assert_equals: expected "0.7 1 " but got "- 0.1 1 "
    189189FAIL Web Animations: property <scale> from neutral to [1.5 1] at (0) should be [1.1 1] assert_equals: expected "1.1 1 " but got "0.7 1 "
    190 FAIL Web Animations: property <scale> from neutral to [1.5 1] at (0.25) should be [1.2 1] assert_equals: expected "1.2 1 " but got "0.9 1 "
    191 FAIL Web Animations: property <scale> from neutral to [1.5 1] at (0.75) should be [1.4 1] assert_equals: expected "1.4 1 " but got "1.35 1 "
     190FAIL Web Animations: property <scale> from neutral to [1.5 1] at (0.25) should be [1.2 1] assert_equals: expected "1.2 1 " but got "1.05 1 "
     191FAIL Web Animations: property <scale> from neutral to [1.5 1] at (0.75) should be [1.4 1] assert_equals: expected "1.4 1 " but got "1.46 1 "
    192192PASS Web Animations: property <scale> from neutral to [1.5 1] at (1) should be [1.5 1]
    193193FAIL Web Animations: property <scale> from neutral to [1.5 1] at (2) should be [1.9 1] assert_equals: expected "1.9 1 " but got "1.5 1 "
  • trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-transforms/animation/translate-interpolation-expected.txt

    r268173 r268615  
    234234PASS CSS Animations: property <translate> from neutral to [20px] at (1) should be [20px]
    235235PASS CSS Animations: property <translate> from neutral to [20px] at (2) should be [30px]
    236 PASS Web Animations: property <translate> from neutral to [20px] at (-1) should be [0px]
     236FAIL Web Animations: property <translate> from neutral to [20px] at (-1) should be [0px] assert_equals: expected "none " but got "- 20px "
    237237FAIL Web Animations: property <translate> from neutral to [20px] at (0) should be [10px] assert_equals: expected "10px " but got "none "
    238 FAIL Web Animations: property <translate> from neutral to [20px] at (0.25) should be [12.5px] assert_equals: expected "12.5px " but got "5px "
    239 FAIL Web Animations: property <translate> from neutral to [20px] at (0.75) should be [17.5px] assert_equals: expected "17.5px " but got "16.25px "
     238FAIL Web Animations: property <translate> from neutral to [20px] at (0.25) should be [12.5px] assert_equals: expected "12.5px " but got "8.75px "
     239FAIL Web Animations: property <translate> from neutral to [20px] at (0.75) should be [17.5px] assert_equals: expected "17.5px " but got "19.06px "
    240240PASS Web Animations: property <translate> from neutral to [20px] at (1) should be [20px]
    241241FAIL Web Animations: property <translate> from neutral to [20px] at (2) should be [30px] assert_equals: expected "30px " but got "20px "
  • trunk/Source/WebCore/ChangeLog

    r268613 r268615  
     12020-10-16  Antoine Quint  <graouts@webkit.org>
     2
     3        Support accelerated animation of individual transform CSS properties
     4        https://bugs.webkit.org/show_bug.cgi?id=217842
     5        <rdar://problem/70391914>
     6
     7        Reviewed by Dean Jackson.
     8
     9        In order to support accelerated animation of individual transform CSS properties, we make a list of the
     10        various animations targeting animation-related properties in GraphicsLayerCA::updateAnimations() and apply
     11        an animation for each of those properties in their expected application order – translate, scale, rotate and
     12        then transform – using Core Animation's additive animation mode.
     13
     14        When one of those properties does not have an animation, we create a non-interpolating base transform value
     15        animation set with both from and to values matching the value set in CSS for this particular property. We use
     16        a new transformMatrixForProperty() method on the GraphicsLayerClient to obtain this value.
     17
     18        We also add a non-additive, non-interpolating identity transform first to make sure all the additive animations
     19        build on top of a neutral transform and not the underlying value applied to the layer.
     20
     21        Finally, when GraphicsLayerCA::setTransform() is updated, we update the animations to ensure that any base
     22        transform value animation is updated to match the current value of the CSS properties contributing to the
     23        compound layer transform.
     24
     25        Tests: webanimations/accelerated-transform-related-animation-property-order.html
     26               webanimations/accelerated-translate-animation-additional-animation-added-in-flight.html
     27               webanimations/accelerated-translate-animation-underlying-transform-changed-in-flight.html
     28               webanimations/accelerated-translate-animation-with-transform.html
     29               webanimations/accelerated-translate-animation.html
     30
     31        * animation/CSSPropertyAnimation.cpp: Add the necessary animationIsAccelerated() overrides for each of the
     32        individual CSS transform property animation wrappers to indicate that accelerated animations are supported.
     33        * platform/graphics/GraphicsLayer.cpp:
     34        (WebCore::GraphicsLayer::validateTransformOperations): Update the ASSERT to check that the animated property
     35        is any of the transform-related properties.
     36        * platform/graphics/GraphicsLayer.h:
     37        (WebCore::TransformAnimationValue::TransformAnimationValue): Add a new constructor that takes a single TransformOperation*
     38        value as input instead of a TransformOperations& so that the values coming from the individual CSS transform properties
     39        can be used to create a TransformAnimationValue in RenderLayerBacking::startAnimation().
     40        * platform/graphics/GraphicsLayerClient.h: Add the new animated property identifiers for the individual CSS transform properties.
     41        (WebCore::animatedPropertyIsTransformOrRelated): Add a new utility to identify any of the transform-related animated property
     42        identifiers.
     43        (WebCore::GraphicsLayerClient::transformMatrixForProperty const): New method called from GraphicsLayerCA::updateAnimations()
     44        to query the client, such as RenderLayerBacking, for the TransformationMatrix representing a given CSS property value to be
     45        used for base transform value non-interpolating animations.
     46        * platform/graphics/ca/GraphicsLayerCA.cpp:
     47        (WebCore::propertyIdToString): Account for the new animated property identifiers.
     48        (WebCore::GraphicsLayerCA::setTransform): If we are currently running a transform-related animation, a change in underlying
     49        transform value means we must re-evaluate all transform-related animations to ensure that the base value transform animations
     50        are current.
     51        (WebCore::GraphicsLayerCA::moveOrCopyAnimations):
     52        (WebCore::GraphicsLayerCA::addAnimation):
     53        (WebCore::GraphicsLayerCA::updateAnimations): When updating animations, keep track of the most recent animation applicable to each
     54        individual CSS transform property and the list of animations targeting the transform CSS property. Then, ensure those animations
     55        are applied in the specified order – translate, scale, rotate and transform – by adding those animations as additive CA animations
     56        with non-interpolating base transform value animations for each property that does not have a specified interpolating animation.
     57        (WebCore::GraphicsLayerCA::isRunningTransformAnimation const): Ensure we also consider paused animations as "running" animations.
     58        (WebCore::GraphicsLayerCA::appendToUncommittedAnimations): Whether a transform animation needs to be run using the additive mode
     59        is now determined in updateAnimations() so we remove all code related to working out whether animations ought to be additive.
     60        (WebCore::GraphicsLayerCA::createTransformAnimationsFromKeyframes): We force the creation of CATransform3D values for individual
     61        CSS transform properties since only this mode guarantees that additivity of such animations will yield the expected result where
     62        the transforms are multiplied rather than simply adding float values of individual components.
     63        * platform/graphics/ca/GraphicsLayerCA.h:
     64        * rendering/RenderLayerBacking.cpp:
     65        (WebCore::RenderLayerBacking::startAnimation): Ensure we start animations for the individual CSS transform properties.
     66        (WebCore::RenderLayerBacking::graphicsLayerToCSSProperty):
     67        (WebCore::RenderLayerBacking::cssToGraphicsLayerProperty):
     68        (WebCore::RenderLayerBacking::transformMatrixForProperty const): Implement the new GraphicsLayerClient method to provide a
     69        matrix that can be used as a value for non-interpolating base value transform animations in GraphicsLayerCA::updateAnimations()
     70        for any of the transform-related CSS properties.
     71        * rendering/RenderLayerBacking.h:
     72        * rendering/RenderLayerCompositor.cpp:
     73        (WebCore::RenderLayerCompositor::requiresCompositingForAnimation const): Ensure that an animation for any of the transform-related
     74        CSS properties yields composition of the target layer.
     75        (WebCore::RenderLayerCompositor::isRunningTransformAnimation const):
     76        * rendering/style/WillChangeData.cpp:
     77        (WebCore::propertyTriggersCompositingOnBoxesOnly): Ensure that setting the will-change CSS property to any of the transform-related
     78        CSS properties yields composition of the target.
     79
    1802020-10-16  Jiewen Tan  <jiewen_tan@apple.com>
    281
  • trunk/Source/WebCore/animation/CSSPropertyAnimation.cpp

    r268516 r268615  
    851851
    852852private:
     853    bool animationIsAccelerated() const final { return true; }
     854
    853855    bool equals(const RenderStyle* a, const RenderStyle* b) const final
    854856    {
     
    866868
    867869private:
     870    bool animationIsAccelerated() const final { return true; }
     871
    868872    bool equals(const RenderStyle* a, const RenderStyle* b) const final
    869873    {
     
    881885
    882886private:
     887    bool animationIsAccelerated() const final { return true; }
     888
    883889    bool equals(const RenderStyle* a, const RenderStyle* b) const final
    884890    {
  • trunk/Source/WebCore/platform/graphics/GraphicsLayer.cpp

    r266342 r268615  
    722722int GraphicsLayer::validateTransformOperations(const KeyframeValueList& valueList, bool& hasBigRotation)
    723723{
    724     ASSERT(valueList.property() == AnimatedPropertyTransform);
     724    ASSERT(animatedPropertyIsTransformOrRelated(valueList.property()));
    725725
    726726    hasBigRotation = false;
  • trunk/Source/WebCore/platform/graphics/GraphicsLayer.h

    r267188 r268615  
    134134    }
    135135
     136    TransformAnimationValue(double keyTime, TransformOperation* value, TimingFunction* timingFunction = nullptr)
     137        : AnimationValue(keyTime, timingFunction)
     138    {
     139        if (value)
     140            m_value.operations().append(value);
     141    }
     142
    136143    std::unique_ptr<AnimationValue> clone() const override
    137144    {
  • trunk/Source/WebCore/platform/graphics/GraphicsLayerClient.h

    r257465 r268615  
    2727
    2828#include "TiledBacking.h"
     29#include "TransformationMatrix.h"
    2930#include <wtf/Forward.h>
    3031#include <wtf/OptionSet.h>
     
    3839class IntPoint;
    3940class IntRect;
    40 class TransformationMatrix;
    4141
    4242enum class GraphicsLayerPaintingPhase {
     
    5252enum AnimatedPropertyID {
    5353    AnimatedPropertyInvalid,
     54    AnimatedPropertyTranslate,
     55    AnimatedPropertyScale,
     56    AnimatedPropertyRotate,
    5457    AnimatedPropertyTransform,
    5558    AnimatedPropertyOpacity,
     
    6063#endif
    6164};
     65
     66inline bool animatedPropertyIsTransformOrRelated(AnimatedPropertyID property)
     67{
     68    return property == AnimatedPropertyTransform || property == AnimatedPropertyTranslate || property == AnimatedPropertyScale || property == AnimatedPropertyRotate;
     69}
    6270
    6371enum LayerTreeAsTextBehaviorFlags {
     
    140148    virtual void logFilledVisibleFreshTile(unsigned) { };
    141149
     150    virtual TransformationMatrix transformMatrixForProperty(AnimatedPropertyID) const { return { }; }
     151
    142152#ifndef NDEBUG
    143153    // RenderLayerBacking overrides this to verify that it is not
  • trunk/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp

    r268483 r268615  
    5757#include <wtf/SetForScope.h>
    5858#include <wtf/SystemTracing.h>
     59#include <wtf/UUID.h>
    5960#include <wtf/text/StringConcatenateNumbers.h>
    6061#include <wtf/text/TextStream.h>
     
    252253{
    253254    switch (property) {
     255    case AnimatedPropertyTranslate:
     256    case AnimatedPropertyScale:
     257    case AnimatedPropertyRotate:
    254258    case AnimatedPropertyTransform:
    255259        return "transform"_s;
     
    658662    GraphicsLayer::setTransform(t);
    659663    noteLayerPropertyChanged(TransformChanged);
     664
     665    // If we are currently running a transform-related animation, a change in underlying
     666    // transform value means we must re-evaluate all transform-related animations to ensure
     667    // that the base value transform animations are current.
     668    if (isRunningTransformAnimation())
     669        noteLayerPropertyChanged(AnimationChanged | CoverageRectChanged);
    660670}
    661671
     
    690700{
    691701    for (auto& animation : m_animations) {
    692         if ((animation.m_property == AnimatedPropertyTransform
     702        if ((animatedPropertyIsTransformOrRelated(animation.m_property)
    693703            || animation.m_property == AnimatedPropertyOpacity
    694704            || animation.m_property == AnimatedPropertyBackgroundColor
     
    10451055
    10461056    bool createdAnimations = false;
    1047     if (valueList.property() == AnimatedPropertyTransform)
     1057    if (animatedPropertyIsTransformOrRelated(valueList.property()))
    10481058        createdAnimations = createTransformAnimationsFromKeyframes(valueList, anim, animationName, Seconds { timeOffset }, boxSize);
    10491059    else if (valueList.property() == AnimatedPropertyFilter) {
     
    28522862void GraphicsLayerCA::updateAnimations()
    28532863{
    2854     // Remove all animations so far.
    2855     for (auto& animation : m_animations)
    2856         removeCAAnimationFromLayer(animation);
    2857 
    2858     // Remove all animations from the list that were pending removal.
    2859     m_animations.removeAllMatching([&](LayerPropertyAnimation animation) {
    2860         return animation.m_pendingRemoval;
    2861     });
    2862 
    2863     // Add all remaining animations.
    2864     for (auto& animation : m_animations) {
     2864    enum class Additive { Yes, No };
     2865    auto addAnimation = [&](LayerPropertyAnimation& animation, Additive additive = Additive::Yes) {
     2866        animation.m_animation->setAdditive(additive == Additive::Yes);
    28652867        setAnimationOnLayer(animation);
    28662868        if (animation.m_playState == PlayState::PausePending || animation.m_playState == PlayState::Paused) {
     
    28692871        } else
    28702872            animation.m_playState = PlayState::Playing;
     2873    };
     2874
     2875    enum class TransformationMatrixSource { UseIdentityMatrix, AskClient };
     2876    auto addBaseValueTransformAnimation = [&](AnimatedPropertyID property, TransformationMatrixSource matrixSource = TransformationMatrixSource::AskClient) {
     2877        // A base value transform animation can either be set to the identity matrix or to read the underlying
     2878        // value from the GraphicsLayerClient. If we didn't explicitly ask for an identity matrix, we can skip
     2879        // the addition of this base value transform animation since it will be a no-op.
     2880        auto matrix = matrixSource == TransformationMatrixSource::UseIdentityMatrix ? TransformationMatrix() : client().transformMatrixForProperty(property);
     2881        if (matrixSource == TransformationMatrixSource::AskClient && matrix.isIdentity())
     2882            return;
     2883
     2884        // A base value transform animation needs to last forever and use the same value for its from and to values.
     2885        auto caAnimation = createPlatformCAAnimation(PlatformCAAnimation::Basic, propertyIdToString(property));
     2886        caAnimation->setDuration(Seconds::infinity().seconds());
     2887        caAnimation->setFromValue(matrix);
     2888        caAnimation->setToValue(matrix);
     2889
     2890        auto animation = LayerPropertyAnimation(WTFMove(caAnimation), "base-transform-" + createCanonicalUUIDString(), property, 0, 0, 0_s);
     2891        // To ensure the base value transform is applied along with all the interpolating animations, we set it to have started
     2892        // as early as possible, which combined with the infinite duration ensures it's current for any given CA media time.
     2893        animation.m_beginTime = Seconds::fromNanoseconds(1);
     2894
     2895        // Additivity will depend on the source of the matrix, if it was explicitly provided as an identity matrix, it
     2896        // is the initial base value transform animation and must override the current transform value for this layer.
     2897        // Otherwise, it is meant to apply the underlying value for one specific transform-related property and be additive
     2898        // to be combined with the other base value transform animations and interpolating animations.
     2899        addAnimation(animation, matrixSource == TransformationMatrixSource::AskClient ? Additive::Yes : Additive::No);
     2900        m_baseValueTransformAnimations.append(WTFMove(animation));
     2901    };
     2902
     2903    // Remove all running CA animations.
     2904    for (auto& animation : m_animations) {
     2905        if (animation.m_playState == PlayState::Playing || animation.m_playState == PlayState::Paused)
     2906            removeCAAnimationFromLayer(animation);
     2907    }
     2908
     2909    // Also remove all the base value transform CA animations.
     2910    for (auto& animation : m_baseValueTransformAnimations)
     2911        removeCAAnimationFromLayer(animation);
     2912
     2913    // Now remove all the animations marked as pending removal and all base value transform animations.
     2914    m_animations.removeAllMatching([&](LayerPropertyAnimation animation) {
     2915        return animation.m_pendingRemoval;
     2916    });
     2917    m_baseValueTransformAnimations.clear();
     2918
     2919    // Now that our list of animations is current, we can separate animations by property so that
     2920    // we can apply them in order. We only need to apply the last animation applied for a given
     2921    // individual transform property, so we keep a reference to that. For animations targeting
     2922    // the transform property itself, we keep them in order since they all need to apply and build
     2923    // on top of each other. Finally, animations that are not transform-related can be applied
     2924    // right away since their order relative to transform animations does not matter.
     2925    LayerPropertyAnimation* translateAnimation = nullptr;
     2926    LayerPropertyAnimation* scaleAnimation = nullptr;
     2927    LayerPropertyAnimation* rotateAnimation = nullptr;
     2928    Vector<LayerPropertyAnimation*> transformAnimations;
     2929
     2930    for (auto& animation : m_animations) {
     2931        switch (animation.m_property) {
     2932        case AnimatedPropertyTranslate:
     2933            translateAnimation = &animation;
     2934            break;
     2935        case AnimatedPropertyScale:
     2936            scaleAnimation = &animation;
     2937            break;
     2938        case AnimatedPropertyRotate:
     2939            rotateAnimation = &animation;
     2940            break;
     2941        case AnimatedPropertyTransform:
     2942            transformAnimations.append(&animation);
     2943            break;
     2944        case AnimatedPropertyOpacity:
     2945        case AnimatedPropertyBackgroundColor:
     2946        case AnimatedPropertyFilter:
     2947#if ENABLE(FILTERS_LEVEL_2)
     2948        case AnimatedPropertyWebkitBackdropFilter:
     2949#endif
     2950            addAnimation(animation, Additive::No);
     2951            break;
     2952        case AnimatedPropertyInvalid:
     2953            ASSERT_NOT_REACHED();
     2954        }
     2955    }
     2956
     2957    // Now we can apply the transform-related animations, taking care to add them in the right order
     2958    // (translate/scale/rotate/transform) and generate non-interpolating base value transform animations
     2959    // for each property that is not otherwise interpolated.
     2960    if (translateAnimation || scaleAnimation || rotateAnimation || !transformAnimations.isEmpty()) {
     2961        // Start with a base identity transform to override the transform applied to the layer and have a
     2962        // sound base to add animations on top of with additivity enabled.
     2963        addBaseValueTransformAnimation(AnimatedPropertyTransform, TransformationMatrixSource::UseIdentityMatrix);
     2964
     2965        // Core Animation might require additive animations to be applied in the reverse order.
     2966#if !PLATFORM(WIN) && !HAVE(CA_WHERE_ADDITIVE_TRANSFORMS_ARE_REVERSED)
     2967        if (translateAnimation)
     2968            addAnimation(*translateAnimation);
     2969        else
     2970            addBaseValueTransformAnimation(AnimatedPropertyTranslate);
     2971
     2972        if (scaleAnimation)
     2973            addAnimation(*scaleAnimation);
     2974        else
     2975            addBaseValueTransformAnimation(AnimatedPropertyScale);
     2976
     2977        if (rotateAnimation)
     2978            addAnimation(*rotateAnimation);
     2979        else
     2980            addBaseValueTransformAnimation(AnimatedPropertyRotate);
     2981
     2982        for (auto* animation : transformAnimations)
     2983            addAnimation(*animation);
     2984        if (transformAnimations.isEmpty())
     2985            addBaseValueTransformAnimation(AnimatedPropertyTransform);
     2986#else
     2987        for (auto* animation : WTF::makeReversedRange(transformAnimations))
     2988            addAnimation(*animation);
     2989        if (transformAnimations.isEmpty())
     2990            addBaseValueTransformAnimation(AnimatedPropertyTransform);
     2991
     2992        if (rotateAnimation)
     2993            addAnimation(*rotateAnimation);
     2994        else
     2995            addBaseValueTransformAnimation(AnimatedPropertyRotate);
     2996
     2997        if (scaleAnimation)
     2998            addAnimation(*scaleAnimation);
     2999        else
     3000            addBaseValueTransformAnimation(AnimatedPropertyScale);
     3001
     3002        if (translateAnimation)
     3003            addAnimation(*translateAnimation);
     3004        else
     3005            addBaseValueTransformAnimation(AnimatedPropertyTranslate);
     3006#endif
    28713007    }
    28723008}
     
    28753011{
    28763012    return m_animations.findMatching([&](LayerPropertyAnimation animation) {
    2877         return animation.m_property == AnimatedPropertyTransform && animation.m_playState == PlayState::Playing;
     3013        return animatedPropertyIsTransformOrRelated(animation.m_property) && (animation.m_playState == PlayState::Playing || animation.m_playState == PlayState::Paused);
    28783014    }) != notFound;
    28793015}
     
    30113147bool GraphicsLayerCA::createAnimationFromKeyframes(const KeyframeValueList& valueList, const Animation* animation, const String& animationName, Seconds timeOffset)
    30123148{
    3013     ASSERT(valueList.property() != AnimatedPropertyTransform && (!supportsAcceleratedFilterAnimations() || valueList.property() != AnimatedPropertyFilter));
     3149    ASSERT(!animatedPropertyIsTransformOrRelated(valueList.property()) && (!supportsAcceleratedFilterAnimations() || valueList.property() != AnimatedPropertyFilter));
    30143150
    30153151    bool valuesOK;
     
    30423178{
    30433179    TransformOperation::OperationType transformOp = isMatrixAnimation ? TransformOperation::MATRIX_3D : operations->operations().at(animationIndex)->type();
    3044 #if !PLATFORM(WIN) && !HAVE(CA_WHERE_ADDITIVE_TRANSFORMS_ARE_REVERSED)
    3045     bool additive = animationIndex > 0;
    3046 #else
    3047     int numAnimations = isMatrixAnimation ? 1 : operations->size();
    3048     bool additive = animationIndex < numAnimations - 1;
    3049 #endif
    30503180
    30513181    RefPtr<PlatformCAAnimation> caAnimation;
    30523182    bool validMatrices = true;
    30533183    if (isKeyframe(valueList)) {
    3054         caAnimation = createKeyframeAnimation(animation, propertyIdToString(valueList.property()), additive);
     3184        caAnimation = createKeyframeAnimation(animation, propertyIdToString(valueList.property()), false);
    30553185        validMatrices = setTransformAnimationKeyframes(valueList, animation, caAnimation.get(), animationIndex, transformOp, isMatrixAnimation, boxSize);
    30563186    } else {
    30573187        if (animation->timingFunction()->isSpringTimingFunction())
    3058             caAnimation = createSpringAnimation(animation, propertyIdToString(valueList.property()), additive);
     3188            caAnimation = createSpringAnimation(animation, propertyIdToString(valueList.property()), false);
    30593189        else
    3060             caAnimation = createBasicAnimation(animation, propertyIdToString(valueList.property()), additive);
     3190            caAnimation = createBasicAnimation(animation, propertyIdToString(valueList.property()), false);
    30613191        validMatrices = setTransformAnimationEndpoints(valueList, animation, caAnimation.get(), animationIndex, transformOp, isMatrixAnimation, boxSize);
    30623192    }
     
    30713201bool GraphicsLayerCA::createTransformAnimationsFromKeyframes(const KeyframeValueList& valueList, const Animation* animation, const String& animationName, Seconds timeOffset, const FloatSize& boxSize)
    30723202{
    3073     ASSERT(valueList.property() == AnimatedPropertyTransform);
     3203    ASSERT(animatedPropertyIsTransformOrRelated(valueList.property()));
    30743204
    30753205    bool hasBigRotation;
     
    30803210
    30813211    // If function lists don't match we do a matrix animation, otherwise we do a component hardware animation.
    3082     bool isMatrixAnimation = listIndex < 0;
     3212    bool isMatrixAnimation = valueList.property() == AnimatedPropertyTransform ? listIndex < 0 : true;
    30833213    int numAnimations = isMatrixAnimation ? 1 : operations->size();
    30843214
    3085 #if !PLATFORM(WIN) && !HAVE(CA_WHERE_ADDITIVE_TRANSFORMS_ARE_REVERSED)
    30863215    for (int animationIndex = 0; animationIndex < numAnimations; ++animationIndex) {
    3087 #else
    3088     // Some versions of CA require animation lists to be applied in reverse order (<rdar://problem/43908047> and <rdar://problem/9112233>).
    3089     for (int animationIndex = numAnimations - 1; animationIndex >= 0; --animationIndex) {
    3090 #endif
    30913216        if (!appendToUncommittedAnimations(valueList, operations, animation, animationName, boxSize, animationIndex, timeOffset, isMatrixAnimation)) {
    30923217            validMatrices = false;
     
    42164341static String animatedPropertyIDAsString(AnimatedPropertyID property)
    42174342{
    4218     if (property == AnimatedPropertyTransform)
     4343    switch (property) {
     4344    case AnimatedPropertyTranslate:
     4345    case AnimatedPropertyScale:
     4346    case AnimatedPropertyRotate:
     4347    case AnimatedPropertyTransform:
    42194348        return "transform";
    4220     if (property == AnimatedPropertyOpacity)
     4349    case AnimatedPropertyOpacity:
    42214350        return "opacity";
    4222     if (property == AnimatedPropertyBackgroundColor)
     4351    case AnimatedPropertyBackgroundColor:
    42234352        return "background-color";
    4224     if (property == AnimatedPropertyFilter)
     4353    case AnimatedPropertyFilter:
    42254354        return "filter";
    4226     if (property == AnimatedPropertyInvalid)
    4227         return "invalid";
    42284355#if ENABLE(FILTERS_LEVEL_2)
    4229     if (property == AnimatedPropertyWebkitBackdropFilter)
     4356    case AnimatedPropertyWebkitBackdropFilter:
    42304357        return "backdrop-filter";
    42314358#endif
     4359    case AnimatedPropertyInvalid:
     4360        return "invalid";
     4361    }
     4362    ASSERT_NOT_REACHED();
    42324363    return "";
    42334364}
  • trunk/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.h

    r268483 r268615  
    598598   
    599599    Vector<LayerPropertyAnimation> m_animations;
     600    Vector<LayerPropertyAnimation> m_baseValueTransformAnimations;
    600601
    601602    Vector<FloatRect> m_dirtyRects;
  • trunk/Source/WebCore/rendering/RenderLayerBacking.cpp

    r268476 r268615  
    35623562{
    35633563    bool hasOpacity = keyframes.containsProperty(CSSPropertyOpacity);
     3564    bool hasRotate = renderer().isBox() && keyframes.containsProperty(CSSPropertyRotate);
     3565    bool hasScale = renderer().isBox() && keyframes.containsProperty(CSSPropertyScale);
     3566    bool hasTranslate = renderer().isBox() && keyframes.containsProperty(CSSPropertyTranslate);
    35643567    bool hasTransform = renderer().isBox() && keyframes.containsProperty(CSSPropertyTransform);
    35653568    bool hasFilter = keyframes.containsProperty(CSSPropertyFilter);
     
    35703573#endif
    35713574
    3572     if (!hasOpacity && !hasTransform && !hasFilter && !hasBackdropFilter)
    3573         return false;
    3574 
     3575    if (!hasOpacity && !hasRotate && !hasScale && !hasTranslate && !hasTransform && !hasFilter && !hasBackdropFilter)
     3576        return false;
     3577
     3578    KeyframeValueList rotateVector(AnimatedPropertyRotate);
     3579    KeyframeValueList scaleVector(AnimatedPropertyScale);
     3580    KeyframeValueList translateVector(AnimatedPropertyTranslate);
    35753581    KeyframeValueList transformVector(AnimatedPropertyTransform);
    35763582    KeyframeValueList opacityVector(AnimatedPropertyOpacity);
     
    35923598       
    35933599        bool isFirstOrLastKeyframe = key == 0 || key == 1;
     3600        if ((hasRotate && isFirstOrLastKeyframe) || currentKeyframe.containsProperty(CSSPropertyRotate))
     3601            rotateVector.insert(makeUnique<TransformAnimationValue>(key, keyframeStyle->rotate(), tf));
     3602
     3603        if ((hasScale && isFirstOrLastKeyframe) || currentKeyframe.containsProperty(CSSPropertyScale))
     3604            scaleVector.insert(makeUnique<TransformAnimationValue>(key, keyframeStyle->scale(), tf));
     3605
     3606        if ((hasTranslate && isFirstOrLastKeyframe) || currentKeyframe.containsProperty(CSSPropertyTranslate))
     3607            translateVector.insert(makeUnique<TransformAnimationValue>(key, keyframeStyle->translate(), tf));
     3608
    35943609        if ((hasTransform && isFirstOrLastKeyframe) || currentKeyframe.containsProperty(CSSPropertyTransform))
    35953610            transformVector.insert(makeUnique<TransformAnimationValue>(key, keyframeStyle->transform(), tf));
     
    36123627    bool didAnimate = false;
    36133628
     3629    if (hasRotate && m_graphicsLayer->addAnimation(rotateVector, snappedIntRect(renderBox()->borderBoxRect()).size(), &animation, keyframes.animationName(), timeOffset))
     3630        didAnimate = true;
     3631
     3632    if (hasScale && m_graphicsLayer->addAnimation(scaleVector, snappedIntRect(renderBox()->borderBoxRect()).size(), &animation, keyframes.animationName(), timeOffset))
     3633        didAnimate = true;
     3634
     3635    if (hasTranslate && m_graphicsLayer->addAnimation(translateVector, snappedIntRect(renderBox()->borderBoxRect()).size(), &animation, keyframes.animationName(), timeOffset))
     3636        didAnimate = true;
     3637
    36143638    if (hasTransform && m_graphicsLayer->addAnimation(transformVector, snappedIntRect(renderBox()->borderBoxRect()).size(), &animation, keyframes.animationName(), timeOffset))
    36153639        didAnimate = true;
     
    37083732    CSSPropertyID cssProperty = CSSPropertyInvalid;
    37093733    switch (property) {
     3734    case AnimatedPropertyTranslate:
     3735        cssProperty = CSSPropertyTranslate;
     3736        break;
     3737    case AnimatedPropertyScale:
     3738        cssProperty = CSSPropertyScale;
     3739        break;
     3740    case AnimatedPropertyRotate:
     3741        cssProperty = CSSPropertyRotate;
     3742        break;
    37103743    case AnimatedPropertyTransform:
    37113744        cssProperty = CSSPropertyTransform;
     
    37343767{
    37353768    switch (cssProperty) {
     3769    case CSSPropertyTranslate:
     3770        return AnimatedPropertyTranslate;
     3771    case CSSPropertyScale:
     3772        return AnimatedPropertyScale;
     3773    case CSSPropertyRotate:
     3774        return AnimatedPropertyRotate;
    37363775    case CSSPropertyTransform:
    37373776        return AnimatedPropertyTransform;
     
    38213860}
    38223861
     3862TransformationMatrix RenderLayerBacking::transformMatrixForProperty(AnimatedPropertyID property) const
     3863{
     3864    auto* box = renderBox();
     3865    if (!box)
     3866        return { };
     3867
     3868    TransformationMatrix matrix;
     3869
     3870    auto applyTransformOperation = [&](TransformOperation* operation) {
     3871        if (operation)
     3872            operation->apply(matrix, snappedIntRect(renderBox()->borderBoxRect()).size());
     3873    };
     3874
     3875    if (property == AnimatedPropertyTranslate)
     3876        applyTransformOperation(renderer().style().translate());
     3877    else if (property == AnimatedPropertyScale)
     3878        applyTransformOperation(renderer().style().scale());
     3879    else if (property == AnimatedPropertyRotate)
     3880        applyTransformOperation(renderer().style().rotate());
     3881    else if (property == AnimatedPropertyTransform)
     3882        renderer().style().transform().apply(snappedIntRect(renderBox()->borderBoxRect()).size(), matrix);
     3883    else
     3884        ASSERT_NOT_REACHED();
     3885
     3886    return matrix;
     3887}
     3888
    38233889} // namespace WebCore
  • trunk/Source/WebCore/rendering/RenderLayerBacking.h

    r267188 r268615  
    252252    LayoutSize subpixelOffsetFromRenderer() const { return m_subpixelOffsetFromRenderer; }
    253253
     254    TransformationMatrix transformMatrixForProperty(AnimatedPropertyID) const final;
     255
    254256#if PLATFORM(IOS_FAMILY)
    255257    bool needsIOSDumpRenderTreeMainFrameRenderViewLayerIsAlwaysOpaqueHack(const GraphicsLayer&) const override;
  • trunk/Source/WebCore/rendering/RenderLayerCompositor.cpp

    r268547 r268615  
    29732973                || effectsStack->isCurrentlyAffectingProperty(CSSPropertyWebkitBackdropFilter)
    29742974#endif
     2975                || effectsStack->isCurrentlyAffectingProperty(CSSPropertyTranslate)
     2976                || effectsStack->isCurrentlyAffectingProperty(CSSPropertyScale)
     2977                || effectsStack->isCurrentlyAffectingProperty(CSSPropertyRotate)
    29752978                || effectsStack->isCurrentlyAffectingProperty(CSSPropertyTransform);
    29762979        }
     
    35183521    if (auto styleable = Styleable::fromRenderer(renderer)) {
    35193522        if (auto* effectsStack = styleable->keyframeEffectStack())
    3520             return effectsStack->isCurrentlyAffectingProperty(CSSPropertyTransform);
     3523            return effectsStack->isCurrentlyAffectingProperty(CSSPropertyTransform)
     3524                || effectsStack->isCurrentlyAffectingProperty(CSSPropertyRotate)
     3525                || effectsStack->isCurrentlyAffectingProperty(CSSPropertyScale)
     3526                || effectsStack->isCurrentlyAffectingProperty(CSSPropertyTranslate);
    35213527    }
    35223528
  • trunk/Source/WebCore/rendering/style/WillChangeData.cpp

    r267985 r268615  
    121121    // always composite if there's no scrollable overflow.
    122122    switch (property) {
     123    case CSSPropertyScale:
     124    case CSSPropertyRotate:
     125    case CSSPropertyTranslate:
    123126    case CSSPropertyTransform:
    124127        return true;
Note: See TracChangeset for help on using the changeset viewer.