blob: cdffd2a5aca1c1c786bf0a74e91e8e770a49d707 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/compositor/layer_owner.h"
#include "base/macros.h"
#include "base/test/null_task_runner.h"
#include "cc/animation/animation_player.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/compositor/compositor.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/layer_animation_observer.h"
#include "ui/compositor/layer_animator.h"
#include "ui/compositor/scoped_animation_duration_scale_mode.h"
#include "ui/compositor/scoped_layer_animation_settings.h"
#include "ui/compositor/test/context_factories_for_test.h"
#include "ui/gfx/native_widget_types.h"
namespace ui {
namespace {
// An animation observer that confirms upon animation completion, that the
// compositor is not null.
class TestLayerAnimationObserver : public ImplicitAnimationObserver {
public:
TestLayerAnimationObserver(Layer* layer) : layer_(layer) {}
~TestLayerAnimationObserver() override {}
// ImplicitAnimationObserver:
void OnImplicitAnimationsCompleted() override {
EXPECT_NE(nullptr, layer_->GetCompositor());
}
private:
Layer* layer_;
DISALLOW_COPY_AND_ASSIGN(TestLayerAnimationObserver);
};
class LayerOwnerForTesting : public LayerOwner {
public:
void DestroyLayerForTesting() { DestroyLayer(); }
};
// Test fixture for LayerOwner tests that require a ui::Compositor.
class LayerOwnerTestWithCompositor : public testing::Test {
public:
LayerOwnerTestWithCompositor();
~LayerOwnerTestWithCompositor() override;
void SetUp() override;
void TearDown() override;
protected:
ui::Compositor* compositor() { return compositor_.get(); }
private:
std::unique_ptr<ui::Compositor> compositor_;
DISALLOW_COPY_AND_ASSIGN(LayerOwnerTestWithCompositor);
};
LayerOwnerTestWithCompositor::LayerOwnerTestWithCompositor() {
}
LayerOwnerTestWithCompositor::~LayerOwnerTestWithCompositor() {
}
void LayerOwnerTestWithCompositor::SetUp() {
scoped_refptr<base::SingleThreadTaskRunner> task_runner =
new base::NullTaskRunner();
ui::ContextFactory* context_factory =
ui::InitializeContextFactoryForTests(false);
compositor_.reset(new ui::Compositor(context_factory, task_runner));
compositor_->SetAcceleratedWidget(gfx::kNullAcceleratedWidget);
}
void LayerOwnerTestWithCompositor::TearDown() {
compositor_.reset();
ui::TerminateContextFactoryForTests();
}
} // namespace
TEST(LayerOwnerTest, RecreateLayerHonorsAnimationTargets) {
LayerOwner owner;
Layer* layer = new Layer(LAYER_SOLID_COLOR);
layer->SetVisible(true);
layer->SetOpacity(1.0f);
layer->SetColor(SK_ColorRED);
owner.SetLayer(layer);
ScopedLayerAnimationSettings settings(layer->GetAnimator());
layer->SetVisible(false);
layer->SetOpacity(0.0f);
layer->SetColor(SK_ColorGREEN);
EXPECT_TRUE(layer->visible());
EXPECT_EQ(1.0f, layer->opacity());
EXPECT_EQ(SK_ColorRED, layer->background_color());
std::unique_ptr<Layer> old_layer(owner.RecreateLayer());
EXPECT_FALSE(owner.layer()->visible());
EXPECT_EQ(0.0f, owner.layer()->opacity());
EXPECT_EQ(SK_ColorGREEN, owner.layer()->background_color());
}
// Tests that when a LAYER_SOLID_COLOR which is not backed by a SolidColorLayer
// that opaqueness and color targets are maintained when the
// LayerOwner::RecreateLayers is called.
TEST(LayerOwnerTest, RecreateLayerSolidColorWithChangedCCLayerHonorsTargets) {
SkColor transparent = SK_ColorTRANSPARENT;
LayerOwner owner;
Layer* layer = new Layer(LAYER_SOLID_COLOR);
owner.SetLayer(layer);
layer->SetFillsBoundsOpaquely(false);
layer->SetColor(transparent);
// Changing the backing layer takes LAYER_SOLID_COLOR off of the normal layer
// flow, need to ensure that set values are maintained.
layer->SwitchCCLayerForTest();
EXPECT_FALSE(layer->fills_bounds_opaquely());
EXPECT_EQ(transparent, layer->background_color());
EXPECT_EQ(transparent, layer->GetTargetColor());
std::unique_ptr<Layer> old_layer(owner.RecreateLayer());
EXPECT_FALSE(owner.layer()->fills_bounds_opaquely());
EXPECT_EQ(transparent, owner.layer()->background_color());
EXPECT_EQ(transparent, owner.layer()->GetTargetColor());
}
TEST(LayerOwnerTest, RecreateRootLayerWithNullCompositor) {
LayerOwner owner;
Layer* layer = new Layer;
owner.SetLayer(layer);
std::unique_ptr<Layer> layer_copy = owner.RecreateLayer();
EXPECT_EQ(nullptr, owner.layer()->GetCompositor());
EXPECT_EQ(nullptr, layer_copy->GetCompositor());
}
TEST(LayerOwnerTest, InvertPropertyRemainSameWithRecreateLayer) {
LayerOwner owner;
Layer* layer = new Layer;
owner.SetLayer(layer);
layer->SetLayerInverted(true);
std::unique_ptr<Layer> old_layer1 = owner.RecreateLayer();
EXPECT_EQ(old_layer1->layer_inverted(), owner.layer()->layer_inverted());
old_layer1->SetLayerInverted(false);
std::unique_ptr<Layer> old_layer2 = owner.RecreateLayer();
EXPECT_EQ(old_layer2->layer_inverted(), owner.layer()->layer_inverted());
}
TEST(LayerOwnerTest, RecreateLayerWithTransform) {
LayerOwner owner;
Layer* layer = new Layer;
owner.SetLayer(layer);
gfx::Transform transform;
transform.Scale(2, 1);
transform.Translate(10, 5);
layer->SetTransform(transform);
std::unique_ptr<Layer> old_layer1 = owner.RecreateLayer();
// Both new layer and original layer have the same transform.
EXPECT_EQ(transform, old_layer1->GetTargetTransform());
EXPECT_EQ(transform, owner.layer()->GetTargetTransform());
// But they're now separated, so changing the old layer's transform
// should not affect the owner's.
owner.layer()->SetTransform(gfx::Transform());
EXPECT_EQ(transform, old_layer1->GetTargetTransform());
std::unique_ptr<Layer> old_layer2 = owner.RecreateLayer();
EXPECT_TRUE(old_layer2->GetTargetTransform().IsIdentity());
EXPECT_TRUE(owner.layer()->GetTargetTransform().IsIdentity());
}
TEST_F(LayerOwnerTestWithCompositor, RecreateRootLayerWithCompositor) {
LayerOwner owner;
Layer* layer = new Layer;
owner.SetLayer(layer);
compositor()->SetRootLayer(layer);
std::unique_ptr<Layer> layer_copy = owner.RecreateLayer();
EXPECT_EQ(compositor(), owner.layer()->GetCompositor());
EXPECT_EQ(owner.layer(), compositor()->root_layer());
EXPECT_EQ(nullptr, layer_copy->GetCompositor());
}
// Tests that recreating the root layer, while one of its children is animating,
// properly updates the compositor. So that compositor is not null for observers
// of animations being cancelled.
TEST_F(LayerOwnerTestWithCompositor, RecreateRootLayerDuringAnimation) {
LayerOwner owner;
Layer* layer = new Layer;
owner.SetLayer(layer);
compositor()->SetRootLayer(layer);
std::unique_ptr<Layer> child(new Layer);
child->SetBounds(gfx::Rect(0, 0, 100, 100));
layer->Add(child.get());
// This observer checks that the compositor of |child| is not null upon
// animation completion.
std::unique_ptr<TestLayerAnimationObserver> observer(
new TestLayerAnimationObserver(child.get()));
std::unique_ptr<ui::ScopedAnimationDurationScaleMode> long_duration_animation(
new ui::ScopedAnimationDurationScaleMode(
ui::ScopedAnimationDurationScaleMode::SLOW_DURATION));
{
ui::ScopedLayerAnimationSettings animation(child->GetAnimator());
animation.SetTransitionDuration(base::TimeDelta::FromMilliseconds(1000));
animation.AddObserver(observer.get());
gfx::Transform transform;
transform.Scale(0.5f, 0.5f);
child->SetTransform(transform);
}
std::unique_ptr<Layer> layer_copy = owner.RecreateLayer();
}
// Tests that recreating a non-root layer, while one of its children is
// animating, properly updates the compositor. So that compositor is not null
// for observers of animations being cancelled.
TEST_F(LayerOwnerTestWithCompositor, RecreateNonRootLayerDuringAnimation) {
std::unique_ptr<Layer> root_layer(new Layer);
compositor()->SetRootLayer(root_layer.get());
LayerOwner owner;
Layer* layer = new Layer;
owner.SetLayer(layer);
root_layer->Add(layer);
std::unique_ptr<Layer> child(new Layer);
child->SetBounds(gfx::Rect(0, 0, 100, 100));
layer->Add(child.get());
// This observer checks that the compositor of |child| is not null upon
// animation completion.
std::unique_ptr<TestLayerAnimationObserver> observer(
new TestLayerAnimationObserver(child.get()));
std::unique_ptr<ui::ScopedAnimationDurationScaleMode> long_duration_animation(
new ui::ScopedAnimationDurationScaleMode(
ui::ScopedAnimationDurationScaleMode::SLOW_DURATION));
{
ui::ScopedLayerAnimationSettings animation(child->GetAnimator());
animation.SetTransitionDuration(base::TimeDelta::FromMilliseconds(1000));
animation.AddObserver(observer.get());
gfx::Transform transform;
transform.Scale(0.5f, 0.5f);
child->SetTransform(transform);
}
std::unique_ptr<Layer> layer_copy = owner.RecreateLayer();
}
// Tests that if LayerOwner-derived class destroys layer, then
// LayerAnimator's player becomes detached from compositor timeline.
TEST_F(LayerOwnerTestWithCompositor, DetachTimelineOnAnimatorDeletion) {
std::unique_ptr<Layer> root_layer(new Layer);
compositor()->SetRootLayer(root_layer.get());
LayerOwnerForTesting owner;
Layer* layer = new Layer;
owner.SetLayer(layer);
layer->SetOpacity(0.5f);
root_layer->Add(layer);
scoped_refptr<cc::AnimationPlayer> player =
layer->GetAnimator()->GetAnimationPlayerForTesting();
EXPECT_TRUE(player);
EXPECT_TRUE(player->animation_timeline());
// Destroying layer/animator must detach animator's player from timeline.
owner.DestroyLayerForTesting();
EXPECT_FALSE(player->animation_timeline());
}
// Tests that if we run threaded opacity animation on already added layer
// then LayerAnimator's player becomes attached to timeline.
TEST_F(LayerOwnerTestWithCompositor,
AttachTimelineIfAnimatorCreatedAfterSetCompositor) {
std::unique_ptr<Layer> root_layer(new Layer);
compositor()->SetRootLayer(root_layer.get());
LayerOwner owner;
Layer* layer = new Layer;
owner.SetLayer(layer);
root_layer->Add(layer);
layer->SetOpacity(0.5f);
scoped_refptr<cc::AnimationPlayer> player =
layer->GetAnimator()->GetAnimationPlayerForTesting();
EXPECT_TRUE(player);
EXPECT_TRUE(player->animation_timeline());
}
} // namespace ui