chromium/cc/trees/layer_tree_host_unittest_animation.cc

// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "cc/trees/layer_tree_host.h"

#include <stdint.h>
#include <climits>

#include "base/functional/bind.h"
#include "base/metrics/statistics_recorder.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "cc/animation/animation.h"
#include "cc/animation/animation_host.h"
#include "cc/animation/animation_id_provider.h"
#include "cc/animation/animation_timeline.h"
#include "cc/animation/element_animations.h"
#include "cc/animation/keyframe_effect.h"
#include "cc/animation/scroll_offset_animation_curve.h"
#include "cc/animation/scroll_offset_animation_curve_factory.h"
#include "cc/animation/scroll_offset_animations.h"
#include "cc/base/completion_event.h"
#include "cc/base/features.h"
#include "cc/layers/layer.h"
#include "cc/layers/layer_impl.h"
#include "cc/test/animation_test_common.h"
#include "cc/test/fake_content_layer_client.h"
#include "cc/test/fake_picture_layer.h"
#include "cc/test/layer_tree_test.h"
#include "cc/trees/effect_node.h"
#include "cc/trees/layer_tree_impl.h"
#include "cc/trees/target_property.h"
#include "cc/trees/transform_node.h"
#include "components/viz/common/quads/compositor_frame.h"
#include "ui/gfx/animation/keyframe/animation_curve.h"
#include "ui/gfx/animation/keyframe/timing_function.h"
#include "ui/gfx/geometry/test/geometry_util.h"
#include "ui/gfx/geometry/transform_operations.h"

namespace cc {
namespace {

#define SAMPLE(curve, time)

class LayerTreeHostAnimationTest : public LayerTreeTest {};

// Makes sure that SetNeedsAnimate does not cause the CommitRequested() state to
// be set.
class LayerTreeHostAnimationTestSetNeedsAnimateShouldNotSetCommitRequested
    : public LayerTreeHostAnimationTest {};

MULTI_THREAD_TEST_F(
    LayerTreeHostAnimationTestSetNeedsAnimateShouldNotSetCommitRequested);

// Trigger a frame with SetNeedsCommit. Then, inside the resulting animate
// callback, request another frame using SetNeedsAnimate. End the test when
// animate gets called yet-again, indicating that the proxy is correctly
// handling the case where SetNeedsAnimate() is called inside the BeginFrame
// flow.
class LayerTreeHostAnimationTestSetNeedsAnimateInsideAnimationCallback
    : public LayerTreeHostAnimationTest {};

SINGLE_AND_MULTI_THREAD_TEST_F(
    LayerTreeHostAnimationTestSetNeedsAnimateInsideAnimationCallback);

// Add a layer animation and confirm that
// LayerTreeHostImpl::UpdateAnimationState does get called.
class LayerTreeHostAnimationTestAddKeyframeModel
    : public LayerTreeHostAnimationTest {};

SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostAnimationTestAddKeyframeModel);

// Add an animation that does not cause damage, followed by an animation that
// does. Confirm that the first animation finishes even though
// enable_early_damage_check should abort draws.
class LayerTreeHostAnimationTestNoDamageAnimation
    : public LayerTreeHostAnimationTest {};

// This behavior is specific to Android WebView, which only uses
// multi-threaded compositor.
MULTI_THREAD_TEST_F(LayerTreeHostAnimationTestNoDamageAnimation);

// Add a layer animation to a layer, but continually fail to draw. Confirm that
// after a while, we do eventually force a draw.
class LayerTreeHostAnimationTestCheckerboardDoesNotStarveDraws
    : public LayerTreeHostAnimationTest {};

// Starvation can only be an issue with the MT compositor.
MULTI_THREAD_TEST_F(LayerTreeHostAnimationTestCheckerboardDoesNotStarveDraws);

// Ensures that animations eventually get deleted.
class LayerTreeHostAnimationTestAnimationsGetDeleted
    : public LayerTreeHostAnimationTest {};

SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostAnimationTestAnimationsGetDeleted);

// Ensure that an animation's timing function is respected.
class LayerTreeHostAnimationTestAddKeyframeModelWithTimingFunction
    : public LayerTreeHostAnimationTest {};

SINGLE_AND_MULTI_THREAD_TEST_F(
    LayerTreeHostAnimationTestAddKeyframeModelWithTimingFunction);

// Ensures that main thread animations have their start times synchronized with
// impl thread animations.
class LayerTreeHostAnimationTestSynchronizeAnimationStartTimes
    : public LayerTreeHostAnimationTest {};

SINGLE_AND_MULTI_THREAD_TEST_F(
    LayerTreeHostAnimationTestSynchronizeAnimationStartTimes);

// Ensures that notify animation finished is called.
class LayerTreeHostAnimationTestAnimationFinishedEvents
    : public LayerTreeHostAnimationTest {};

SINGLE_AND_MULTI_THREAD_TEST_F(
    LayerTreeHostAnimationTestAnimationFinishedEvents);

// Ensures that when opacity is being animated, this value does not cause the
// subtree to be skipped.
class LayerTreeHostAnimationTestDoNotSkipLayersWithAnimatedOpacity
    : public LayerTreeHostAnimationTest {};

SINGLE_AND_MULTI_THREAD_TEST_F(
    LayerTreeHostAnimationTestDoNotSkipLayersWithAnimatedOpacity);

// Layers added to tree with existing active animations should have the
// animation correctly recognized.
class LayerTreeHostAnimationTestLayerAddedWithAnimation
    : public LayerTreeHostAnimationTest {};

SINGLE_AND_MULTI_THREAD_TEST_F(
    LayerTreeHostAnimationTestLayerAddedWithAnimation);

class LayerTreeHostAnimationTestCancelAnimateCommit
    : public LayerTreeHostAnimationTest {};

MULTI_THREAD_TEST_F(LayerTreeHostAnimationTestCancelAnimateCommit);

class LayerTreeHostAnimationTestForceRedraw
    : public LayerTreeHostAnimationTest {};

MULTI_THREAD_TEST_F(LayerTreeHostAnimationTestForceRedraw);

class LayerTreeHostAnimationTestAnimateAfterSetNeedsCommit
    : public LayerTreeHostAnimationTest {};

MULTI_THREAD_TEST_F(LayerTreeHostAnimationTestAnimateAfterSetNeedsCommit);

// Animations should not be started when frames are being skipped due to
// checkerboard.
class LayerTreeHostAnimationTestCheckerboardDoesntStartAnimations
    : public LayerTreeHostAnimationTest {};

MULTI_THREAD_TEST_F(
    LayerTreeHostAnimationTestCheckerboardDoesntStartAnimations);

// Verifies that a scroll offset animation sends scroll offset updates back to
// the main thread.
class LayerTreeHostAnimationTestScrollOffsetChangesArePropagated
    : public LayerTreeHostAnimationTest {};

SINGLE_AND_MULTI_THREAD_TEST_F(
    LayerTreeHostAnimationTestScrollOffsetChangesArePropagated);

// Verifies that when a main thread scrolling reason gets added, the
// notification to takover the animation on the main thread gets sent.
class LayerTreeHostAnimationTestScrollOffsetAnimationTakeover
    : public LayerTreeHostAnimationTest {};

// TODO(crbug.com/40655283):  [BlinkGenPropertyTrees] Scroll Animation should be
// taken over from cc when scroll is unpromoted.
// MULTI_THREAD_TEST_F(LayerTreeHostAnimationTestScrollOffsetAnimationTakeover);

// Verifies that an impl-only scroll offset animation gets updated when the
// scroll offset is adjusted on the main thread.
class LayerTreeHostAnimationTestScrollOffsetAnimationAdjusted
    : public LayerTreeHostAnimationTest {};

MULTI_THREAD_TEST_F(LayerTreeHostAnimationTestScrollOffsetAnimationAdjusted);

// Tests that presentation-time requested from the main-thread is attached to
// the correct frame (i.e. activation needs to happen before the
// presentation-request is attached to the frame).
class LayerTreeHostPresentationDuringAnimation
    : public LayerTreeHostAnimationTest {};

// Disabled on ChromeOS due to test flakiness. See https://crbug.com/1246422
#if !BUILDFLAG(IS_CHROMEOS)
MULTI_THREAD_TEST_F(LayerTreeHostPresentationDuringAnimation);
#endif

// Verifies that when the main thread removes a scroll animation and sets a new
// scroll position, the active tree takes on exactly this new scroll position
// after activation, and the main thread doesn't receive a spurious scroll
// delta.
class LayerTreeHostAnimationTestScrollOffsetAnimationRemoval
    : public LayerTreeHostAnimationTest {};

MULTI_THREAD_TEST_F(LayerTreeHostAnimationTestScrollOffsetAnimationRemoval);

// Verifies that the state of a scroll animation is tracked correctly on the
// main and compositor thread and that the KeyframeModel is removed when
// the scroll animation completes. This is a regression test for
// https://crbug.com/962346 and demonstrates the necessity of
// LayerTreeHost::AnimateLayers for https://crbug.com/762717.
class LayerTreeHostAnimationTestScrollOffsetAnimationCompletion
    : public LayerTreeHostAnimationTest {};

MULTI_THREAD_TEST_F(LayerTreeHostAnimationTestScrollOffsetAnimationCompletion);

// When animations are simultaneously added to an existing layer and to a new
// layer, they should start at the same time, even when there's already a
// running animation on the existing layer.
class LayerTreeHostAnimationTestAnimationsAddedToNewAndExistingLayers
    : public LayerTreeHostAnimationTest {};

// This test blocks activation which is not supported for single thread mode.
MULTI_THREAD_BLOCKNOTIFY_TEST_F(
    LayerTreeHostAnimationTestAnimationsAddedToNewAndExistingLayers);

class LayerTreeHostAnimationTestAddKeyframeModelAfterAnimating
    : public LayerTreeHostAnimationTest {};

SINGLE_AND_MULTI_THREAD_TEST_F(
    LayerTreeHostAnimationTestAddKeyframeModelAfterAnimating);

class LayerTreeHostAnimationTestRemoveKeyframeModel
    : public LayerTreeHostAnimationTest {};

// Disabled on ChromeOS due to test flakiness. See https://crbug.com/1246422
#if !BUILDFLAG(IS_CHROMEOS)
SINGLE_THREAD_TEST_F(LayerTreeHostAnimationTestRemoveKeyframeModel);
#endif

MULTI_THREAD_TEST_F(LayerTreeHostAnimationTestRemoveKeyframeModel);

class LayerTreeHostAnimationTestIsAnimating
    : public LayerTreeHostAnimationTest {};

// TODO(https://issues.chromium.org/41490442): Flaky on Linux/ASAN/debug.
#if BUILDFLAG(IS_LINUX) || defined(ADDRESS_SANITIZER) || !defined(NDEBUG)
SINGLE_THREAD_TEST_F(LayerTreeHostAnimationTestIsAnimating);
#else
SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostAnimationTestIsAnimating);
#endif

class LayerTreeHostAnimationTestAnimationFinishesDuringCommit
    : public LayerTreeHostAnimationTest {};

// An animation finishing during commit can only happen when we have a separate
// compositor thread.
MULTI_THREAD_TEST_F(LayerTreeHostAnimationTestAnimationFinishesDuringCommit);

class LayerTreeHostAnimationTestImplSideInvalidation
    : public LayerTreeHostAnimationTest {};

MULTI_THREAD_TEST_F(LayerTreeHostAnimationTestImplSideInvalidation);

class LayerTreeHostAnimationTestImplSideInvalidationWithoutCommit
    : public LayerTreeHostAnimationTest {};

class ImplSideInvalidationWithoutCommitTestOpacity
    : public LayerTreeHostAnimationTestImplSideInvalidationWithoutCommit {};

MULTI_THREAD_TEST_F(ImplSideInvalidationWithoutCommitTestOpacity);

class ImplSideInvalidationWithoutCommitTestTransform
    : public LayerTreeHostAnimationTestImplSideInvalidationWithoutCommit {};

MULTI_THREAD_TEST_F(ImplSideInvalidationWithoutCommitTestTransform);

class ImplSideInvalidationWithoutCommitTestFilter
    : public LayerTreeHostAnimationTestImplSideInvalidationWithoutCommit {};

MULTI_THREAD_TEST_F(ImplSideInvalidationWithoutCommitTestFilter);

class ImplSideInvalidationWithoutCommitTestScroll
    : public LayerTreeHostAnimationTestImplSideInvalidationWithoutCommit {};

MULTI_THREAD_TEST_F(ImplSideInvalidationWithoutCommitTestScroll);

class LayerTreeHostAnimationTestNotifyAnimationFinished
    : public LayerTreeHostAnimationTest {};

SINGLE_AND_MULTI_THREAD_TEST_F(
    LayerTreeHostAnimationTestNotifyAnimationFinished);

// Check that transform sync happens correctly at commit when we remove and add
// a different animation animation to an element.
class LayerTreeHostAnimationTestChangeAnimation
    : public LayerTreeHostAnimationTest {};

SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostAnimationTestChangeAnimation);

// Check that SetTransformIsPotentiallyAnimatingChanged is called
// if we destroy ElementAnimations.
class LayerTreeHostAnimationTestSetPotentiallyAnimatingOnLacDestruction
    : public LayerTreeHostAnimationTest {};

MULTI_THREAD_TEST_F(
    LayerTreeHostAnimationTestSetPotentiallyAnimatingOnLacDestruction);

// Check that we invalidate property trees on Animation::SetNeedsCommit.
class LayerTreeHostAnimationTestRebuildPropertyTreesOnAnimationSetNeedsCommit
    : public LayerTreeHostAnimationTest {};

MULTI_THREAD_TEST_F(
    LayerTreeHostAnimationTestRebuildPropertyTreesOnAnimationSetNeedsCommit);

class LayerTreeHostTestPauseRendering : public LayerTreeHostAnimationTest {};

MULTI_THREAD_TEST_F(LayerTreeHostTestPauseRendering);

}  // namespace
}  // namespace cc