#include "cc/trees/tree_synchronizer.h"
#include <stddef.h>
#include <algorithm>
#include <memory>
#include <set>
#include <utility>
#include <vector>
#include "base/containers/contains.h"
#include "base/format_macros.h"
#include "base/memory/ptr_util.h"
#include "base/memory/raw_ptr.h"
#include "base/task/single_thread_task_runner.h"
#include "cc/animation/animation_host.h"
#include "cc/layers/layer.h"
#include "cc/layers/layer_impl.h"
#include "cc/layers/picture_layer.h"
#include "cc/test/animation_test_common.h"
#include "cc/test/fake_content_layer_client.h"
#include "cc/test/fake_impl_task_runner_provider.h"
#include "cc/test/fake_layer_tree_host.h"
#include "cc/test/fake_rendering_stats_instrumentation.h"
#include "cc/test/stub_layer_tree_host_single_thread_client.h"
#include "cc/test/test_task_graph_runner.h"
#include "cc/trees/compositor_commit_data.h"
#include "cc/trees/effect_node.h"
#include "cc/trees/scroll_node.h"
#include "cc/trees/single_thread_proxy.h"
#include "cc/trees/task_runner_provider.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace cc {
namespace {
bool AreScrollOffsetsEqual(const SyncedScrollOffset* a,
const SyncedScrollOffset* b) {
return a->ActiveBase() == b->ActiveBase() &&
a->PendingBase() == b->PendingBase() && a->Delta() == b->Delta() &&
a->PendingDelta() == b->PendingDelta();
}
class MockLayerImpl : public LayerImpl {
public:
static std::unique_ptr<MockLayerImpl> Create(LayerTreeImpl* tree_impl,
int layer_id) {
return base::WrapUnique(new MockLayerImpl(tree_impl, layer_id));
}
~MockLayerImpl() override {
if (layer_impl_destruction_list_)
layer_impl_destruction_list_->push_back(id());
}
void SetLayerImplDestructionList(std::vector<int>* list) {
layer_impl_destruction_list_ = list;
}
private:
MockLayerImpl(LayerTreeImpl* tree_impl, int layer_id)
: LayerImpl(tree_impl, layer_id), layer_impl_destruction_list_(nullptr) {}
raw_ptr<std::vector<int>> layer_impl_destruction_list_;
};
class MockLayer : public Layer {
public:
static scoped_refptr<MockLayer> Create(
std::vector<int>* layer_impl_destruction_list) {
return base::WrapRefCounted(new MockLayer(layer_impl_destruction_list));
}
std::unique_ptr<LayerImpl> CreateLayerImpl(
LayerTreeImpl* tree_impl) const override {
return MockLayerImpl::Create(tree_impl, id());
}
void PushPropertiesTo(LayerImpl* layer_impl,
const CommitState& commit_state,
const ThreadUnsafeCommitState& unsafe_state) override {
Layer::PushPropertiesTo(layer_impl, commit_state, unsafe_state);
MockLayerImpl* mock_layer_impl = static_cast<MockLayerImpl*>(layer_impl);
mock_layer_impl->SetLayerImplDestructionList(layer_impl_destruction_list_);
}
private:
explicit MockLayer(std::vector<int>* layer_impl_destruction_list)
: layer_impl_destruction_list_(layer_impl_destruction_list) {}
~MockLayer() override = default;
raw_ptr<std::vector<int>> layer_impl_destruction_list_;
};
void ExpectTreesAreIdentical(Layer* root_layer,
LayerImpl* root_layer_impl,
LayerTreeImpl* tree_impl) {
auto layer_iter = root_layer->layer_tree_host()->begin();
auto layer_impl_iter = tree_impl->begin();
for (; layer_iter != root_layer->layer_tree_host()->end();
++layer_iter, ++layer_impl_iter) {
Layer* layer = *layer_iter;
LayerImpl* layer_impl = *layer_impl_iter;
ASSERT_TRUE(layer);
ASSERT_TRUE(layer_impl);
EXPECT_EQ(layer->id(), layer_impl->id());
EXPECT_EQ(layer_impl->layer_tree_impl(), tree_impl);
EXPECT_EQ(layer->non_fast_scrollable_region(),
layer_impl->non_fast_scrollable_region());
}
}
class TreeSynchronizerTest : public testing::Test {
public:
void ResetLayerTreeHost(const LayerTreeSettings& settings) {
host_.reset();
host_ = FakeLayerTreeHost::Create(&client_, &task_graph_runner_,
animation_host_.get(), settings);
host_->InitializeSingleThreaded(
&single_thread_client_,
base::SingleThreadTaskRunner::GetCurrentDefault());
host_->host_impl()->CreatePendingTree();
}
scoped_refptr<Layer> SetupScrollLayer() {
FakeLayerTreeHostImpl* host_impl = host_->host_impl();
scoped_refptr<Layer> layer_tree_root = Layer::Create();
scoped_refptr<Layer> scroll_layer = Layer::Create();
ElementId scroll_element_id = ElementId(5);
scroll_layer->SetElementId(scroll_element_id);
layer_tree_root->AddChild(scroll_layer);
scroll_layer->SetScrollable(gfx::Size(1, 1));
scroll_layer->SetBounds(gfx::Size(10, 10));
host_->SetRootLayer(layer_tree_root);
host_->BuildPropertyTreesForTesting();
host_->CommitAndCreatePendingTree();
host_impl->ActivateSyncTree();
ExpectTreesAreIdentical(layer_tree_root.get(),
host_impl->active_tree()->root_layer(),
host_impl->active_tree());
return scroll_layer;
}
protected:
TreeSynchronizerTest()
: animation_host_(AnimationHost::CreateForTesting(ThreadInstance::MAIN)) {
LayerTreeSettings settings;
ResetLayerTreeHost(settings);
}
const FakeLayerTreeHost* const_host() const { return host_.get(); }
FakeLayerTreeHostClient client_;
StubLayerTreeHostSingleThreadClient single_thread_client_;
TestTaskGraphRunner task_graph_runner_;
std::unique_ptr<AnimationHost> animation_host_;
std::unique_ptr<FakeLayerTreeHost> host_;
};
TEST_F(TreeSynchronizerTest, SyncNullTree) {
TreeSynchronizer::SynchronizeTrees(*const_host()->pending_commit_state(),
host_->GetThreadUnsafeCommitState(),
host_->pending_tree());
EXPECT_TRUE(!host_->pending_tree()->root_layer());
}
TEST_F(TreeSynchronizerTest, SyncSimpleTreeFromEmpty) {
scoped_refptr<Layer> layer_tree_root = Layer::Create();
layer_tree_root->AddChild(Layer::Create());
layer_tree_root->AddChild(Layer::Create());
host_->SetRootLayer(layer_tree_root);
host_->BuildPropertyTreesForTesting();
TreeSynchronizer::SynchronizeTrees(*const_host()->pending_commit_state(),
host_->GetThreadUnsafeCommitState(),
host_->pending_tree());
LayerImpl* root = host_->pending_tree()->root_layer();
EXPECT_TRUE(base::Contains(
host_->pending_tree()->LayersThatShouldPushProperties(), root));
ExpectTreesAreIdentical(layer_tree_root.get(),
host_->pending_tree()->root_layer(),
host_->pending_tree());
}
TEST_F(TreeSynchronizerTest, SyncSimpleTreeAndPushPropertiesFromEmpty) {
scoped_refptr<Layer> layer_tree_root = Layer::Create();
layer_tree_root->AddChild(Layer::Create());
layer_tree_root->AddChild(Layer::Create());
host_->SetRootLayer(layer_tree_root);
host_->BuildPropertyTreesForTesting();
TreeSynchronizer::SynchronizeTrees(*const_host()->pending_commit_state(),
host_->GetThreadUnsafeCommitState(),
host_->pending_tree());
LayerImpl* root = host_->pending_tree()->root_layer();
EXPECT_TRUE(base::Contains(
host_->pending_tree()->LayersThatShouldPushProperties(), root));
ExpectTreesAreIdentical(layer_tree_root.get(),
host_->pending_tree()->root_layer(),
host_->pending_tree());
TreeSynchronizer::PushLayerProperties(*host_->GetPendingCommitState(),
host_->GetThreadUnsafeCommitState(),
host_->pending_tree());
TreeSynchronizer::SynchronizeTrees(host_->pending_tree(),
host_->active_tree());
TreeSynchronizer::PushLayerProperties(host_->pending_tree(),
host_->active_tree());
EXPECT_FALSE(base::Contains(
host_->pending_tree()->LayersThatShouldPushProperties(), root));
layer_tree_root->SetNeedsPushProperties();
EXPECT_TRUE(base::Contains(
const_host()->pending_commit_state()->layers_that_should_push_properties,
layer_tree_root.get()));
TreeSynchronizer::SynchronizeTrees(*const_host()->pending_commit_state(),
host_->GetThreadUnsafeCommitState(),
host_->pending_tree());
TreeSynchronizer::PushLayerProperties(*host_->GetPendingCommitState(),
host_->GetThreadUnsafeCommitState(),
host_->pending_tree());
EXPECT_TRUE(base::Contains(
host_->pending_tree()->LayersThatShouldPushProperties(), root));
}
TEST_F(TreeSynchronizerTest, SyncSimpleTreeReusingLayers) {
std::vector<int> layer_impl_destruction_list;
scoped_refptr<Layer> layer_tree_root =
MockLayer::Create(&layer_impl_destruction_list);
layer_tree_root->AddChild(MockLayer::Create(&layer_impl_destruction_list));
layer_tree_root->AddChild(MockLayer::Create(&layer_impl_destruction_list));
int second_layer_impl_id = layer_tree_root->children()[1]->id();
host_->SetRootLayer(layer_tree_root);
host_->BuildPropertyTreesForTesting();
TreeSynchronizer::SynchronizeTrees(*const_host()->pending_commit_state(),
host_->GetThreadUnsafeCommitState(),
host_->pending_tree());
LayerImpl* layer_impl_tree_root = host_->pending_tree()->root_layer();
EXPECT_TRUE(
base::Contains(host_->pending_tree()->LayersThatShouldPushProperties(),
layer_impl_tree_root));
ExpectTreesAreIdentical(layer_tree_root.get(), layer_impl_tree_root,
host_->pending_tree());
TreeSynchronizer::PushLayerProperties(*host_->GetPendingCommitState(),
host_->GetThreadUnsafeCommitState(),
host_->pending_tree());
layer_tree_root->children()[0]->AddChild(
MockLayer::Create(&layer_impl_destruction_list));
layer_tree_root->children()[1]->RemoveFromParent();
host_->BuildPropertyTreesForTesting();
TreeSynchronizer::SynchronizeTrees(*const_host()->pending_commit_state(),
host_->GetThreadUnsafeCommitState(),
host_->pending_tree());
layer_impl_tree_root = host_->pending_tree()->root_layer();
ExpectTreesAreIdentical(layer_tree_root.get(), layer_impl_tree_root,
host_->pending_tree());
ASSERT_EQ(1u, layer_impl_destruction_list.size());
EXPECT_EQ(second_layer_impl_id, layer_impl_destruction_list[0]);
host_->pending_tree()->DetachLayers();
}
TEST_F(TreeSynchronizerTest, SyncSimpleTreeAndTrackStackingOrderChange) {
std::vector<int> layer_impl_destruction_list;
scoped_refptr<Layer> layer_tree_root =
MockLayer::Create(&layer_impl_destruction_list);
scoped_refptr<Layer> child2 = MockLayer::Create(&layer_impl_destruction_list);
layer_tree_root->AddChild(MockLayer::Create(&layer_impl_destruction_list));
layer_tree_root->AddChild(child2);
int child1_id = layer_tree_root->children()[0]->id();
int child2_id = layer_tree_root->children()[1]->id();
host_->SetRootLayer(layer_tree_root);
host_->BuildPropertyTreesForTesting();
TreeSynchronizer::SynchronizeTrees(*const_host()->pending_commit_state(),
host_->GetThreadUnsafeCommitState(),
host_->active_tree());
LayerImpl* layer_impl_tree_root = host_->active_tree()->root_layer();
ExpectTreesAreIdentical(layer_tree_root.get(), layer_impl_tree_root,
host_->active_tree());
TreeSynchronizer::PushLayerProperties(*host_->GetPendingCommitState(),
host_->GetThreadUnsafeCommitState(),
host_->active_tree());
host_->active_tree()->ResetAllChangeTracking();
child2->RemoveFromParent();
layer_tree_root->AddChild(child2);
host_->BuildPropertyTreesForTesting();
TreeSynchronizer::SynchronizeTrees(*const_host()->pending_commit_state(),
host_->GetThreadUnsafeCommitState(),
host_->active_tree());
layer_impl_tree_root = host_->active_tree()->root_layer();
ExpectTreesAreIdentical(layer_tree_root.get(), layer_impl_tree_root,
host_->active_tree());
host_->active_tree()->SetPropertyTrees(
*layer_tree_root->layer_tree_host()->property_trees());
TreeSynchronizer::PushLayerProperties(*host_->GetPendingCommitState(),
host_->GetThreadUnsafeCommitState(),
host_->active_tree());
EXPECT_FALSE(layer_impl_tree_root->LayerPropertyChanged());
EXPECT_FALSE(
host_->active_tree()->LayerById(child1_id)->LayerPropertyChanged());
EXPECT_TRUE(
host_->active_tree()->LayerById(child2_id)->LayerPropertyChanged());
EXPECT_FALSE(host_->active_tree()
->LayerById(child2_id)
->LayerPropertyChangedFromPropertyTrees());
EXPECT_TRUE(host_->active_tree()
->LayerById(child2_id)
->LayerPropertyChangedNotFromPropertyTrees());
host_->active_tree()->DetachLayers();
}
TEST_F(TreeSynchronizerTest, SyncSimpleTreeAndProperties) {
scoped_refptr<Layer> layer_tree_root = Layer::Create();
layer_tree_root->AddChild(Layer::Create());
layer_tree_root->AddChild(Layer::Create());
host_->SetRootLayer(layer_tree_root);
gfx::Size root_bounds = gfx::Size(10, 12);
layer_tree_root->SetBounds(root_bounds);
gfx::Size second_child_bounds = gfx::Size(25, 53);
layer_tree_root->children()[1]->SetBounds(second_child_bounds);
int second_child_id = layer_tree_root->children()[1]->id();
host_->BuildPropertyTreesForTesting();
TreeSynchronizer::SynchronizeTrees(*const_host()->pending_commit_state(),
host_->GetThreadUnsafeCommitState(),
host_->active_tree());
LayerImpl* layer_impl_tree_root = host_->active_tree()->root_layer();
ExpectTreesAreIdentical(layer_tree_root.get(), layer_impl_tree_root,
host_->active_tree());
TreeSynchronizer::PushLayerProperties(*host_->GetPendingCommitState(),
host_->GetThreadUnsafeCommitState(),
host_->active_tree());
EXPECT_EQ(root_bounds, layer_impl_tree_root->bounds());
gfx::Size second_layer_impl_child_bounds =
layer_impl_tree_root->layer_tree_impl()
->LayerById(second_child_id)
->bounds();
EXPECT_EQ(second_child_bounds.width(),
second_layer_impl_child_bounds.width());
EXPECT_EQ(second_child_bounds.height(),
second_layer_impl_child_bounds.height());
}
TEST_F(TreeSynchronizerTest, ReuseLayerImplsAfterStructuralChange) {
std::vector<int> layer_impl_destruction_list;
scoped_refptr<Layer> layer_tree_root =
MockLayer::Create(&layer_impl_destruction_list);
layer_tree_root->AddChild(MockLayer::Create(&layer_impl_destruction_list));
scoped_refptr<Layer> layer_a = layer_tree_root->children()[0];
layer_a->AddChild(MockLayer::Create(&layer_impl_destruction_list));
scoped_refptr<Layer> layer_b = layer_a->children()[0];
layer_b->AddChild(MockLayer::Create(&layer_impl_destruction_list));
scoped_refptr<Layer> layer_c = layer_b->children()[0];
layer_b->AddChild(MockLayer::Create(&layer_impl_destruction_list));
scoped_refptr<Layer> layer_d = layer_b->children()[1];
host_->SetRootLayer(layer_tree_root);
host_->BuildPropertyTreesForTesting();
TreeSynchronizer::SynchronizeTrees(*const_host()->pending_commit_state(),
host_->GetThreadUnsafeCommitState(),
host_->active_tree());
LayerImpl* layer_impl_tree_root = host_->active_tree()->root_layer();
ExpectTreesAreIdentical(layer_tree_root.get(), layer_impl_tree_root,
host_->active_tree());
TreeSynchronizer::PushLayerProperties(*host_->GetPendingCommitState(),
host_->GetThreadUnsafeCommitState(),
host_->active_tree());
layer_tree_root->RemoveAllChildren();
layer_d->RemoveAllChildren();
layer_tree_root->AddChild(layer_d);
layer_a->RemoveAllChildren();
layer_d->AddChild(layer_a);
layer_c->RemoveAllChildren();
layer_d->AddChild(layer_c);
layer_b->RemoveAllChildren();
layer_c->AddChild(layer_b);
host_->BuildPropertyTreesForTesting();
TreeSynchronizer::SynchronizeTrees(*const_host()->pending_commit_state(),
host_->GetThreadUnsafeCommitState(),
host_->active_tree());
layer_impl_tree_root = host_->active_tree()->root_layer();
ExpectTreesAreIdentical(layer_tree_root.get(), layer_impl_tree_root,
host_->active_tree());
EXPECT_EQ(0u, layer_impl_destruction_list.size());
host_->active_tree()->DetachLayers();
}
TEST_F(TreeSynchronizerTest, SyncSimpleTreeThenDestroy) {
std::vector<int> layer_impl_destruction_list;
scoped_refptr<Layer> old_layer_tree_root =
MockLayer::Create(&layer_impl_destruction_list);
old_layer_tree_root->AddChild(
MockLayer::Create(&layer_impl_destruction_list));
old_layer_tree_root->AddChild(
MockLayer::Create(&layer_impl_destruction_list));
host_->SetRootLayer(old_layer_tree_root);
int old_tree_root_layer_id = old_layer_tree_root->id();
int old_tree_first_child_layer_id = old_layer_tree_root->children()[0]->id();
int old_tree_second_child_layer_id = old_layer_tree_root->children()[1]->id();
host_->BuildPropertyTreesForTesting();
TreeSynchronizer::SynchronizeTrees(*const_host()->pending_commit_state(),
host_->GetThreadUnsafeCommitState(),
host_->active_tree());
LayerImpl* layer_impl_tree_root = host_->active_tree()->root_layer();
ExpectTreesAreIdentical(old_layer_tree_root.get(), layer_impl_tree_root,
host_->active_tree());
TreeSynchronizer::PushLayerProperties(*host_->GetPendingCommitState(),
host_->GetThreadUnsafeCommitState(),
host_->active_tree());
old_layer_tree_root->RemoveAllChildren();
scoped_refptr<Layer> new_layer_tree_root = Layer::Create();
host_->SetRootLayer(new_layer_tree_root);
host_->BuildPropertyTreesForTesting();
TreeSynchronizer::SynchronizeTrees(*const_host()->pending_commit_state(),
host_->GetThreadUnsafeCommitState(),
host_->active_tree());
layer_impl_tree_root = host_->active_tree()->root_layer();
ExpectTreesAreIdentical(new_layer_tree_root.get(), layer_impl_tree_root,
host_->active_tree());
ASSERT_EQ(3u, layer_impl_destruction_list.size());
EXPECT_TRUE(
base::Contains(layer_impl_destruction_list, old_tree_root_layer_id));
EXPECT_TRUE(base::Contains(layer_impl_destruction_list,
old_tree_first_child_layer_id));
EXPECT_TRUE(base::Contains(layer_impl_destruction_list,
old_tree_second_child_layer_id));
}
TEST_F(TreeSynchronizerTest, SyncMaskLayer) {
scoped_refptr<Layer> layer_tree_root = Layer::Create();
layer_tree_root->AddChild(Layer::Create());
layer_tree_root->AddChild(Layer::Create());
layer_tree_root->AddChild(Layer::Create());
FakeContentLayerClient client;
scoped_refptr<PictureLayer> mask_layer = PictureLayer::Create(&client);
layer_tree_root->children()[0]->SetMaskLayer(mask_layer);
host_->SetRootLayer(layer_tree_root);
host_->BuildPropertyTreesForTesting();
host_->CommitAndCreateLayerImplTree();
LayerImpl* layer_impl_tree_root = host_->active_tree()->root_layer();
ExpectTreesAreIdentical(layer_tree_root.get(), layer_impl_tree_root,
host_->active_tree());
layer_tree_root->children()[0]->SetMaskLayer(nullptr);
host_->BuildPropertyTreesForTesting();
host_->CommitAndCreateLayerImplTree();
layer_impl_tree_root = host_->active_tree()->root_layer();
ExpectTreesAreIdentical(layer_tree_root.get(), layer_impl_tree_root,
host_->active_tree());
layer_impl_tree_root = host_->active_tree()->root_layer();
ExpectTreesAreIdentical(layer_tree_root.get(), layer_impl_tree_root,
host_->active_tree());
layer_impl_tree_root = host_->active_tree()->root_layer();
ExpectTreesAreIdentical(layer_tree_root.get(), layer_impl_tree_root,
host_->active_tree());
host_->active_tree()->DetachLayers();
}
TEST_F(TreeSynchronizerTest, SynchronizeCurrentlyScrollingNode) {
LayerTreeSettings settings;
FakeLayerTreeHostImplClient client;
FakeImplTaskRunnerProvider task_runner_provider;
FakeRenderingStatsInstrumentation stats_instrumentation;
TestTaskGraphRunner task_graph_runner;
FakeLayerTreeHostImpl* host_impl = host_->host_impl();
scoped_refptr<Layer> layer_tree_root = Layer::Create();
scoped_refptr<Layer> scroll_layer = Layer::Create();
scoped_refptr<Layer> transient_scroll_layer = Layer::Create();
layer_tree_root->AddChild(transient_scroll_layer);
transient_scroll_layer->AddChild(scroll_layer);
ElementId scroll_element_id = ElementId(5);
scroll_layer->SetElementId(scroll_element_id);
transient_scroll_layer->SetScrollable(gfx::Size(1, 1));
scroll_layer->SetScrollable(gfx::Size(1, 1));
host_->SetRootLayer(layer_tree_root);
host_->BuildPropertyTreesForTesting();
host_->CommitAndCreatePendingTree();
host_impl->ActivateSyncTree();
ExpectTreesAreIdentical(layer_tree_root.get(),
host_impl->active_tree()->root_layer(),
host_impl->active_tree());
ScrollNode* scroll_node =
host_impl->active_tree()->property_trees()->scroll_tree_mutable().Node(
scroll_layer->scroll_tree_index());
host_impl->active_tree()->SetCurrentlyScrollingNode(scroll_node);
transient_scroll_layer->SetScrollable(gfx::Size(0, 0));
host_->BuildPropertyTreesForTesting();
host_impl->CreatePendingTree();
host_->CommitAndCreatePendingTree();
host_impl->ActivateSyncTree();
EXPECT_EQ(scroll_layer->scroll_tree_index(),
host_impl->active_tree()->CurrentlyScrollingNode()->id);
}
TEST_F(TreeSynchronizerTest, SynchronizeScrollTreeScrollOffsetMap) {
LayerTreeSettings settings;
FakeLayerTreeHostImplClient client;
FakeImplTaskRunnerProvider task_runner_provider;
FakeRenderingStatsInstrumentation stats_instrumentation;
TestTaskGraphRunner task_graph_runner;
FakeLayerTreeHostImpl* host_impl = host_->host_impl();
scoped_refptr<Layer> layer_tree_root = Layer::Create();
scoped_refptr<Layer> scroll_layer = Layer::Create();
scoped_refptr<Layer> transient_scroll_layer = Layer::Create();
ElementId scroll_element_id = ElementId(5);
scroll_layer->SetElementId(scroll_element_id);
layer_tree_root->AddChild(transient_scroll_layer);
transient_scroll_layer->AddChild(scroll_layer);
ElementId transient_scroll_element_id = ElementId(7);
transient_scroll_layer->SetElementId(transient_scroll_element_id);
transient_scroll_layer->SetScrollable(gfx::Size(1, 1));
scroll_layer->SetScrollable(gfx::Size(1, 1));
transient_scroll_layer->SetScrollOffset(gfx::PointF(1, 2));
scroll_layer->SetScrollOffset(gfx::PointF(10, 20));
host_->SetRootLayer(layer_tree_root);
host_->BuildPropertyTreesForTesting();
host_->CommitAndCreatePendingTree();
host_impl->ActivateSyncTree();
ExpectTreesAreIdentical(layer_tree_root.get(),
host_impl->active_tree()->root_layer(),
host_impl->active_tree());
scoped_refptr<SyncedScrollOffset> scroll_layer_offset =
new SyncedScrollOffset;
scroll_layer_offset->PushMainToPending(scroll_layer->scroll_offset());
scroll_layer_offset->PushPendingToActive();
EXPECT_TRUE(AreScrollOffsetsEqual(
scroll_layer_offset.get(),
host_impl->active_tree()
->property_trees()
->scroll_tree()
.GetSyncedScrollOffset(scroll_layer->element_id())));
scoped_refptr<SyncedScrollOffset> transient_scroll_layer_offset =
new SyncedScrollOffset;
transient_scroll_layer_offset->PushMainToPending(
transient_scroll_layer->scroll_offset());
transient_scroll_layer_offset->PushPendingToActive();
EXPECT_TRUE(AreScrollOffsetsEqual(
transient_scroll_layer_offset.get(),
host_impl->active_tree()
->property_trees()
->scroll_tree()
.GetSyncedScrollOffset(transient_scroll_layer->element_id())));
LayerImpl* scroll_layer_impl =
host_impl->active_tree()->LayerById(scroll_layer->id());
ScrollTree& scroll_tree =
host_impl->active_tree()->property_trees()->scroll_tree_mutable();
scroll_tree.SetScrollOffset(scroll_layer_impl->element_id(),
gfx::PointF(20, 30));
std::unique_ptr<CompositorCommitData> commit_data(new CompositorCommitData());
scroll_tree.CollectScrollDeltas(
commit_data.get(), ElementId(), settings.commit_fractional_scroll_deltas,
base::flat_map<ElementId, TargetSnapAreaElementIds>(),
nullptr);
host_->proxy()->SetNeedsCommit();
host_->ApplyCompositorChanges(commit_data.get());
EXPECT_EQ(gfx::PointF(20, 30), scroll_layer->scroll_offset());
scroll_layer->SetScrollOffset(gfx::PointF(100, 100));
scroll_tree.SetScrollOffset(scroll_layer_impl->element_id(),
gfx::PointF(40, 50));
host_impl->active_tree()->SetCurrentlyScrollingNode(
scroll_tree.Node(scroll_layer_impl->scroll_tree_index()));
transient_scroll_layer->RemoveFromParent();
layer_tree_root->AddChild(scroll_layer);
host_->BuildPropertyTreesForTesting();
host_impl->CreatePendingTree();
host_->CommitAndCreatePendingTree();
host_impl->ActivateSyncTree();
EXPECT_EQ(scroll_layer->scroll_tree_index(),
host_impl->active_tree()->CurrentlyScrollingNode()->id);
scroll_layer_offset->SetCurrent(gfx::PointF(20, 30));
scroll_layer_offset->PullDeltaForMainThread( false);
scroll_layer_offset->SetCurrent(gfx::PointF(40, 50));
scroll_layer_offset->PushMainToPending(gfx::PointF(100, 100));
scroll_layer_offset->PushPendingToActive();
EXPECT_TRUE(AreScrollOffsetsEqual(
scroll_layer_offset.get(),
host_impl->active_tree()
->property_trees()
->scroll_tree()
.GetSyncedScrollOffset(scroll_layer->element_id())));
EXPECT_EQ(nullptr,
host_impl->active_tree()
->property_trees()
->scroll_tree()
.GetSyncedScrollOffset(transient_scroll_layer->element_id()));
}
TEST_F(TreeSynchronizerTest, RefreshPropertyTreesCachedData) {
LayerTreeSettings settings;
FakeLayerTreeHostImplClient client;
FakeImplTaskRunnerProvider task_runner_provider;
FakeRenderingStatsInstrumentation stats_instrumentation;
TestTaskGraphRunner task_graph_runner;
FakeLayerTreeHostImpl* host_impl = host_->host_impl();
scoped_refptr<Layer> layer_tree_root = Layer::Create();
scoped_refptr<Layer> transform_layer = Layer::Create();
gfx::Transform scale_transform;
scale_transform.Scale3d(2.f, 2.f, 2.f);
transform_layer->SetTransform(scale_transform);
layer_tree_root->AddChild(transform_layer);
host_->SetRootLayer(layer_tree_root);
host_->BuildPropertyTreesForTesting();
host_->CommitAndCreatePendingTree();
host_impl->ActivateSyncTree();
float maximum_animation_scale = 123.f;
bool animation_affected_by_invalid_scale = true;
host_impl->active_tree()
->property_trees()
->SetMaximumAnimationToScreenScaleForTesting(
transform_layer->transform_tree_index(), maximum_animation_scale,
animation_affected_by_invalid_scale);
EXPECT_EQ(
maximum_animation_scale,
host_impl->active_tree()->property_trees()->MaximumAnimationToScreenScale(
transform_layer->transform_tree_index()));
EXPECT_TRUE(host_impl->active_tree()
->property_trees()
->AnimationAffectedByInvalidScale(
transform_layer->transform_tree_index()));
host_impl->CreatePendingTree();
host_->CommitAndCreatePendingTree();
host_impl->ActivateSyncTree();
EXPECT_EQ(
2.0f,
host_impl->active_tree()->property_trees()->MaximumAnimationToScreenScale(
transform_layer->transform_tree_index()));
EXPECT_FALSE(host_impl->active_tree()
->property_trees()
->AnimationAffectedByInvalidScale(
transform_layer->transform_tree_index()));
}
TEST_F(TreeSynchronizerTest, RoundedScrollDeltasOnCommit) {
LayerTreeSettings settings;
settings.commit_fractional_scroll_deltas = false;
ResetLayerTreeHost(settings);
FakeLayerTreeHostImpl* host_impl = host_->host_impl();
InputHandler::Create(static_cast<CompositorDelegateForInput&>(*host_impl));
scoped_refptr<Layer> scroll_layer = SetupScrollLayer();
LayerImpl* scroll_layer_impl =
host_impl->active_tree()->LayerById(scroll_layer->id());
scroll_layer_impl->ScrollBy(gfx::Vector2dF(0, 1.75f));
std::unique_ptr<CompositorCommitData> commit_data =
host_impl->ProcessCompositorDeltas(
nullptr);
ASSERT_EQ(1u, commit_data->scrolls.size());
EXPECT_EQ(2.f, commit_data->scrolls[0].scroll_delta.y());
}
TEST_F(TreeSynchronizerTest, PreserveFractionalScrollDeltasOnCommit) {
LayerTreeSettings settings;
settings.commit_fractional_scroll_deltas = true;
ResetLayerTreeHost(settings);
FakeLayerTreeHostImpl* host_impl = host_->host_impl();
InputHandler::Create(static_cast<CompositorDelegateForInput&>(*host_impl));
scoped_refptr<Layer> scroll_layer = SetupScrollLayer();
LayerImpl* scroll_layer_impl =
host_impl->active_tree()->LayerById(scroll_layer->id());
scroll_layer_impl->ScrollBy(gfx::Vector2dF(0, 1.75f));
std::unique_ptr<CompositorCommitData> commit_data =
host_impl->ProcessCompositorDeltas(
nullptr);
ASSERT_EQ(1u, commit_data->scrolls.size());
EXPECT_EQ(1.75f, commit_data->scrolls[0].scroll_delta.y());
}
}
}