Changeset 222129 in webkit


Ignore:
Timestamp:
Sep 16, 2017 5:33:04 AM (7 years ago)
Author:
Antti Koivisto
Message:

Computing animated style should not require renderers
https://bugs.webkit.org/show_bug.cgi?id=171926
<rdar://problem/34428035>

Reviewed by Sam Weinig.

Source/WebCore:

CSS animation system is now element rather than renderer based. This allows cleaning up
style resolution and render tree update code.

This also fixes bug animation doesn't run if display property is animated from one rendered type
to another. Added a test case for this.

Test: transitions/transition-display-property-2.html

  • page/animation/CSSAnimationController.cpp:

(WebCore::CSSAnimationController::updateAnimations):

Pass in the old style instead of getting it from the renderer.
Factor to return the animated style as a return value.

  • page/animation/CSSAnimationController.h:
  • rendering/RenderElement.cpp:

(WebCore::RenderElement::RenderElement):
(WebCore::RenderElement::willBeDestroyed):

Animation are now canceled by RenderTreeUpdater::tearDownRenderers.

  • rendering/RenderElement.h:

(WebCore::RenderElement::hasInitialAnimatedStyle const): Deleted.
(WebCore::RenderElement::setHasInitialAnimatedStyle): Deleted.

We no longer need to this concept.

  • style/RenderTreeUpdater.cpp:

(WebCore::RenderTreeUpdater::updateElementRenderer):
(WebCore::RenderTreeUpdater::createRenderer):

We now get correct animated style from style resolution in all cases so we don't need to compute
it separately for new renderers.

(WebCore::RenderTreeUpdater::tearDownRenderers):

Cancel animations when render tree is fully torn down. Keep them when updating style.

  • style/RenderTreeUpdater.h:
  • style/StyleTreeResolver.cpp:

(WebCore::Style::TreeResolver::createAnimatedElementUpdate):

We can now compute animated style without renderer. Special cases dealing with rendererless case
can be removed.

LayoutTests:

  • transitions/transition-display-property-2-expected.html: Added.
  • transitions/transition-display-property-2.html: Added.
  • transitions/transition-display-property.html:
Location:
trunk
Files:
2 added
12 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r222127 r222129  
     12017-09-16  Antti Koivisto  <antti@apple.com>
     2
     3        Computing animated style should not require renderers
     4        https://bugs.webkit.org/show_bug.cgi?id=171926
     5        <rdar://problem/34428035>
     6
     7        Reviewed by Sam Weinig.
     8
     9        * transitions/transition-display-property-2-expected.html: Added.
     10        * transitions/transition-display-property-2.html: Added.
     11        * transitions/transition-display-property.html:
     12
    1132017-09-16  Carlos Garcia Campos  <cgarcia@igalia.com>
    214
  • trunk/LayoutTests/transitions/transition-display-property.html

    r222104 r222129  
    66<script>
    77var test = document.querySelector("test");
    8 var count = 0;
    9 function testUntilComplete()
    10 {
    11     if (test.offsetWidth == 10 || ++count == 10)
    12         testRunner.notifyDone();
    13     else
    14         setTimeout(testUntilComplete, 0.1);
    15 }
    168
    179if (window.testRunner) {
    1810    testRunner.waitUntilDone();
    19     testUntilComplete();
     11    test.ontransitionend = () => testRunner.notifyDone();
    2012}
    2113test.offsetWidth;
  • trunk/Source/WebCore/ChangeLog

    r222126 r222129  
     12017-09-16  Antti Koivisto  <antti@apple.com>
     2
     3        Computing animated style should not require renderers
     4        https://bugs.webkit.org/show_bug.cgi?id=171926
     5        <rdar://problem/34428035>
     6
     7        Reviewed by Sam Weinig.
     8
     9        CSS animation system is now element rather than renderer based. This allows cleaning up
     10        style resolution and render tree update code.
     11
     12        This also fixes bug animation doesn't run if display property is animated from one rendered type
     13        to another. Added a test case for this.
     14
     15        Test: transitions/transition-display-property-2.html
     16
     17        * page/animation/CSSAnimationController.cpp:
     18        (WebCore::CSSAnimationController::updateAnimations):
     19
     20            Pass in the old style instead of getting it from the renderer.
     21            Factor to return the animated style as a return value.
     22
     23        * page/animation/CSSAnimationController.h:
     24        * rendering/RenderElement.cpp:
     25        (WebCore::RenderElement::RenderElement):
     26        (WebCore::RenderElement::willBeDestroyed):
     27
     28            Animation are now canceled by RenderTreeUpdater::tearDownRenderers.
     29
     30        * rendering/RenderElement.h:
     31        (WebCore::RenderElement::hasInitialAnimatedStyle const): Deleted.
     32        (WebCore::RenderElement::setHasInitialAnimatedStyle): Deleted.
     33
     34            We no longer need to this concept.
     35
     36        * style/RenderTreeUpdater.cpp:
     37        (WebCore::RenderTreeUpdater::updateElementRenderer):
     38        (WebCore::RenderTreeUpdater::createRenderer):
     39
     40            We now get correct animated style from style resolution in all cases so we don't need to compute
     41            it separately for new renderers.
     42
     43        (WebCore::RenderTreeUpdater::tearDownRenderers):
     44
     45            Cancel animations when render tree is fully torn down. Keep them when updating style.
     46
     47        * style/RenderTreeUpdater.h:
     48        * style/StyleTreeResolver.cpp:
     49        (WebCore::Style::TreeResolver::createAnimatedElementUpdate):
     50
     51            We can now compute animated style without renderer. Special cases dealing with rendererless case
     52            can be removed.
     53
    1542017-09-15  Carlos Garcia Campos  <cgarcia@igalia.com>
    255
  • trunk/Source/WebCore/page/animation/CSSAnimationController.cpp

    r222104 r222129  
    638638}
    639639
    640 bool CSSAnimationController::updateAnimations(Element& element, const RenderStyle& newStyle, std::unique_ptr<RenderStyle>& animatedStyle)
    641 {
    642     auto* renderer = element.renderer();
    643     auto* oldStyle = (renderer && renderer->hasInitializedStyle()) ? &renderer->style() : nullptr;
    644     if ((!oldStyle || (!oldStyle->animations() && !oldStyle->transitions())) && (!newStyle.animations() && !newStyle.transitions()))
    645         return false;
     640AnimationUpdate CSSAnimationController::updateAnimations(Element& element, const RenderStyle& newStyle, const RenderStyle* oldStyle)
     641{
     642    bool hasOrHadAnimations = (oldStyle && oldStyle->hasAnimationsOrTransitions()) || newStyle.hasAnimationsOrTransitions();
     643    if (!hasOrHadAnimations)
     644        return { };
    646645
    647646    if (element.document().pageCacheState() != Document::NotInPageCache)
    648         return false;
     647        return { };
    649648
    650649    // Don't run transitions when printing.
    651650    if (element.document().renderView()->printing())
    652         return false;
     651        return { };
    653652
    654653    // Fetch our current set of implicit animations from a hashtable. We then compare them
     
    658657
    659658    CompositeAnimation& compositeAnimation = m_data->ensureCompositeAnimation(element);
    660     bool animationStateChanged = compositeAnimation.animate(element, oldStyle, newStyle, animatedStyle);
    661 
     659    auto update = compositeAnimation.animate(element, oldStyle, newStyle);
     660
     661    auto* renderer = element.renderer();
    662662    if ((renderer && renderer->parent()) || newStyle.animations() || (oldStyle && oldStyle->animations())) {
    663663        auto& frameView = *element.document().view();
     
    668668    }
    669669
    670     return animationStateChanged;
     670    return update;
    671671}
    672672
  • trunk/Source/WebCore/page/animation/CSSAnimationController.h

    r222104 r222129  
    3131#include "AnimationBase.h"
    3232#include "CSSPropertyNames.h"
     33#include "RenderStyle.h"
    3334#include <wtf/Forward.h>
    3435
     
    4142class LayoutRect;
    4243class RenderElement;
    43 class RenderStyle;
     44
     45struct AnimationUpdate {
     46#if !COMPILER_SUPPORTS(NSDMI_FOR_AGGREGATES)
     47    AnimationUpdate() = default;
     48    AnimationUpdate(std::unique_ptr<RenderStyle> style, bool stateChanged)
     49        : style(WTFMove(style))
     50        , stateChanged(stateChanged)
     51    { }
     52#endif
     53    std::unique_ptr<RenderStyle> style;
     54    bool stateChanged { false };
     55};
    4456
    4557class CSSAnimationController {
     
    5062
    5163    void cancelAnimations(Element&);
    52     bool updateAnimations(Element&, const RenderStyle& newStyle, std::unique_ptr<RenderStyle>& animatedStyle);
     64    AnimationUpdate updateAnimations(Element&, const RenderStyle& newStyle, const RenderStyle* oldStyle);
    5365    std::unique_ptr<RenderStyle> animatedStyleForRenderer(RenderElement&);
    5466
  • trunk/Source/WebCore/page/animation/CompositeAnimation.cpp

    r222104 r222129  
    288288}
    289289
    290 bool CompositeAnimation::animate(Element& element, const RenderStyle* currentStyle, const RenderStyle& targetStyle, std::unique_ptr<RenderStyle>& blendedStyle)
     290AnimationUpdate CompositeAnimation::animate(Element& element, const RenderStyle* currentStyle, const RenderStyle& targetStyle)
    291291{
    292292    // We don't do any transitions if we don't have a currentStyle (on startup).
     
    298298    bool forceStackingContext = false;
    299299
     300    std::unique_ptr<RenderStyle> animatedStyle;
     301
    300302    if (currentStyle) {
    301303        // Now that we have transition objects ready, let them know about the new goal state.  We want them
     
    304306        for (auto& transition : m_transitions.values()) {
    305307            bool didBlendStyle = false;
    306             if (transition->animate(*this, targetStyle, blendedStyle, didBlendStyle))
     308            if (transition->animate(*this, targetStyle, animatedStyle, didBlendStyle))
    307309                animationStateChanged = true;
    308310
     
    311313        }
    312314
    313         if (blendedStyle && checkForStackingContext) {
     315        if (animatedStyle && checkForStackingContext) {
    314316            // Note that this is similar to code in StyleResolver::adjustRenderStyle() but only needs to consult
    315317            // animatable properties that can trigger stacking context.
    316             if (blendedStyle->opacity() < 1.0f
    317                 || blendedStyle->hasTransformRelatedProperty()
    318                 || blendedStyle->hasMask()
    319                 || blendedStyle->clipPath()
    320                 || blendedStyle->boxReflect()
    321                 || blendedStyle->hasFilter()
     318            if (animatedStyle->opacity() < 1.0f
     319                || animatedStyle->hasTransformRelatedProperty()
     320                || animatedStyle->hasMask()
     321                || animatedStyle->clipPath()
     322                || animatedStyle->boxReflect()
     323                || animatedStyle->hasFilter()
    322324#if ENABLE(FILTERS_LEVEL_2)
    323                 || blendedStyle->hasBackdropFilter()
     325                || animatedStyle->hasBackdropFilter()
    324326#endif
    325327                )
     
    334336        if (keyframeAnim) {
    335337            bool didBlendStyle = false;
    336             if (keyframeAnim->animate(*this, targetStyle, blendedStyle, didBlendStyle))
     338            if (keyframeAnim->animate(*this, targetStyle, animatedStyle, didBlendStyle))
    337339                animationStateChanged = true;
    338340
     
    346348    // the user agent must act as if the will-change property ([css-will-change-1]) on the element additionally
    347349    // includes all the properties animated by the animation.
    348     if (forceStackingContext && blendedStyle) {
    349         if (blendedStyle->hasAutoZIndex())
    350             blendedStyle->setZIndex(0);
    351     }
    352 
    353     return animationStateChanged;
     350    if (forceStackingContext && animatedStyle) {
     351        if (animatedStyle->hasAutoZIndex())
     352            animatedStyle->setZIndex(0);
     353    }
     354
     355    return { WTFMove(animatedStyle), animationStateChanged };
    354356}
    355357
  • trunk/Source/WebCore/page/animation/CompositeAnimation.h

    r222104 r222129  
    2929#pragma once
    3030
     31#include "CSSAnimationController.h"
    3132#include "ImplicitAnimation.h"
    3233#include "KeyframeAnimation.h"
     
    5556    void clearElement();
    5657
    57     bool animate(Element&, const RenderStyle* currentStyle, const RenderStyle& targetStyle, std::unique_ptr<RenderStyle>& blendedStyle);
     58    AnimationUpdate animate(Element&, const RenderStyle* currentStyle, const RenderStyle& targetStyle);
    5859    std::unique_ptr<RenderStyle> getAnimatedStyle() const;
    5960    bool computeExtentOfTransformAnimation(LayoutRect&) const;
  • trunk/Source/WebCore/rendering/RenderElement.cpp

    r222104 r222129  
    2727
    2828#include "AXObjectCache.h"
    29 #include "CSSAnimationController.h"
    3029#include "ContentData.h"
    3130#include "CursorList.h"
     
    103102    , m_ancestorLineBoxDirty(false)
    104103    , m_hasInitializedStyle(false)
    105     , m_hasInitialAnimatedStyle(false)
    106104    , m_renderInlineAlwaysCreatesLineBoxes(false)
    107105    , m_renderBoxNeedsLazyRepaint(false)
     
    11051103        view().frameView().removeSlowRepaintObject(this);
    11061104
    1107     if (element())
    1108         animation().cancelAnimations(*element());
    1109 
    11101105    destroyLeftoverChildren();
    11111106
  • trunk/Source/WebCore/rendering/RenderElement.h

    r222104 r222129  
    132132    void setStyleInternal(RenderStyle&& style) { m_style = WTFMove(style); }
    133133
    134     bool hasInitialAnimatedStyle() const { return m_hasInitialAnimatedStyle; }
    135     void setHasInitialAnimatedStyle(bool b) { m_hasInitialAnimatedStyle = b; }
    136 
    137134    // Repaint only if our old bounds and new bounds are different. The caller may pass in newBounds and newOutlineBox if they are known.
    138135    bool repaintAfterLayoutIfNeeded(const RenderLayerModelObject* repaintContainer, const LayoutRect& oldBounds, const LayoutRect& oldOutlineBox, const LayoutRect* newBoundsPtr = nullptr, const LayoutRect* newOutlineBoxPtr = nullptr);
     
    330327    unsigned m_ancestorLineBoxDirty : 1;
    331328    unsigned m_hasInitializedStyle : 1;
    332     unsigned m_hasInitialAnimatedStyle : 1;
    333329
    334330    unsigned m_renderInlineAlwaysCreatesLineBoxes : 1;
  • trunk/Source/WebCore/style/RenderTreeUpdater.cpp

    r222104 r222129  
    308308            renderTreePosition().invalidateNextSibling();
    309309        }
    310         tearDownRenderers(element, TeardownType::KeepHoverAndActive);
     310
     311        // display:none cancels animations.
     312        auto teardownType = update.style->display() == NONE ? TeardownType::RendererUpdateCancelingAnimations : TeardownType::RendererUpdate;
     313        tearDownRenderers(element, teardownType);
    311314    }
    312315
     
    396399
    397400    element.setRenderer(newRenderer);
    398 
    399     auto& initialStyle = newRenderer->style();
    400     std::unique_ptr<RenderStyle> animatedStyle;
    401     newRenderer->animation().updateAnimations(element, initialStyle, animatedStyle);
    402     if (animatedStyle) {
    403         newRenderer->setStyleInternal(WTFMove(*animatedStyle));
    404         newRenderer->setHasInitialAnimatedStyle(true);
    405     }
    406401
    407402    newRenderer->initializeStyle();
     
    526521}
    527522
     523void RenderTreeUpdater::tearDownRenderers(Element& root)
     524{
     525    tearDownRenderers(root, TeardownType::Full);
     526}
     527
    528528void RenderTreeUpdater::tearDownRenderers(Element& root, TeardownType teardownType)
    529529{
     
    538538    };
    539539
     540    auto& animationController = root.document().frame()->animation();
     541
    540542    auto pop = [&] (unsigned depth) {
    541543        while (teardownStack.size() > depth) {
    542544            auto& element = *teardownStack.takeLast();
    543545
    544             if (teardownType != TeardownType::KeepHoverAndActive)
     546            if (teardownType == TeardownType::Full || teardownType == TeardownType::RendererUpdateCancelingAnimations)
     547                animationController.cancelAnimations(element);
     548
     549            if (teardownType == TeardownType::Full)
    545550                element.clearHoverAndActiveStatusBeforeDetachingRenderer();
     551
    546552            element.clearStyleDerivedDataBeforeDetachingRenderer();
    547553
  • trunk/Source/WebCore/style/RenderTreeUpdater.h

    r222104 r222129  
    4848    void commit(std::unique_ptr<const Style::Update>);
    4949
    50     enum class TeardownType { Normal, KeepHoverAndActive };
    51     static void tearDownRenderers(Element&, TeardownType = TeardownType::Normal);
     50    static void tearDownRenderers(Element&);
    5251    static void tearDownRenderer(Text&);
    5352
     
    8483    void popParentsToDepth(unsigned depth);
    8584
     85    enum class TeardownType { Full, RendererUpdate, RendererUpdateCancelingAnimations };
     86    static void tearDownRenderers(Element&, TeardownType);
     87
    8688    RenderView& renderView();
    8789
  • trunk/Source/WebCore/style/StyleTreeResolver.cpp

    r222104 r222129  
    242242ElementUpdate TreeResolver::createAnimatedElementUpdate(std::unique_ptr<RenderStyle> newStyle, Element& element, Change parentChange)
    243243{
     244    auto& animationController = element.document().frame()->animation();
     245
     246    auto* oldStyle = renderOrDisplayContentsStyle(element);
     247    auto animationUpdate = animationController.updateAnimations(element, *newStyle, oldStyle);
     248
     249    if (animationUpdate.style)
     250        newStyle = WTFMove(animationUpdate.style);
     251
     252    auto change = oldStyle ? determineChange(*oldStyle, *newStyle) : Detach;
     253
    244254    auto validity = element.styleValidity();
    245     bool recompositeLayer = element.styleResolutionShouldRecompositeLayer();
    246 
    247     auto makeUpdate = [&] (std::unique_ptr<RenderStyle> style, Change change) {
    248         if (validity >= Validity::SubtreeInvalid)
    249             change = std::max(change, validity == Validity::SubtreeAndRenderersInvalid ? Detach : Force);
    250         if (parentChange >= Force)
    251             change = std::max(change, parentChange);
    252         return ElementUpdate { WTFMove(style), change, recompositeLayer };
    253     };
    254 
    255     auto* renderer = element.renderer();
    256 
    257     bool shouldReconstruct = validity >= Validity::SubtreeAndRenderersInvalid || parentChange == Detach;
    258     if (shouldReconstruct)
    259         return makeUpdate(WTFMove(newStyle), Detach);
    260 
    261     if (!renderer) {
    262         auto change = Detach;
    263         if (auto* oldStyle = renderOrDisplayContentsStyle(element))
    264             change = determineChange(*oldStyle, *newStyle);
    265         return makeUpdate(WTFMove(newStyle), change);
    266     }
    267 
    268     std::unique_ptr<RenderStyle> animatedStyle;
    269     if (element.document().frame()->animation().updateAnimations(element, *newStyle, animatedStyle))
    270         recompositeLayer = true;
    271 
    272     if (animatedStyle) {
    273         auto change = determineChange(renderer->style(), *animatedStyle);
    274         if (renderer->hasInitialAnimatedStyle()) {
    275             renderer->setHasInitialAnimatedStyle(false);
    276             // When we initialize a newly created renderer with initial animated style we don't inherit it to descendants.
    277             // The first animation frame needs to correct this.
    278             // FIXME: We should compute animated style correctly during initial style resolution when we don't have renderers yet.
    279             //        https://bugs.webkit.org/show_bug.cgi?id=171926
    280             change = std::max(change, Inherit);
    281         }
    282         // If animation forces render tree reconstruction pass the original style. The animation will be applied on renderer construction.
    283         // FIXME: We should always use the animated style here.
    284         auto style = change == Detach ? WTFMove(newStyle) : WTFMove(animatedStyle);
    285         return makeUpdate(WTFMove(style), change);
    286     }
    287 
    288     auto change = determineChange(renderer->style(), *newStyle);
    289     return makeUpdate(WTFMove(newStyle), change);
     255    if (validity >= Validity::SubtreeInvalid)
     256        change = std::max(change, validity == Validity::SubtreeAndRenderersInvalid ? Detach : Force);
     257    if (parentChange >= Force)
     258        change = std::max(change, parentChange);
     259
     260    bool shouldRecompositeLayer = element.styleResolutionShouldRecompositeLayer() || animationUpdate.stateChanged;
     261
     262    return { WTFMove(newStyle), change, shouldRecompositeLayer };
    290263}
    291264
Note: See TracChangeset for help on using the changeset viewer.