| Index: cc/blimp/compositor_state_deserializer_unittest.cc
|
| diff --git a/cc/blimp/compositor_state_deserializer_unittest.cc b/cc/blimp/compositor_state_deserializer_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..3d86f3193b07b9f8da06046b56fee4863587afa7
|
| --- /dev/null
|
| +++ b/cc/blimp/compositor_state_deserializer_unittest.cc
|
| @@ -0,0 +1,421 @@
|
| +// Copyright 2016 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 "compositor_state_deserializer.h"
|
| +
|
| +#include "base/run_loop.h"
|
| +#include "cc/animation/animation_host.h"
|
| +#include "cc/blimp/compositor_proto_state.h"
|
| +#include "cc/blimp/compositor_state_deserializer_client.h"
|
| +#include "cc/blimp/layer_tree_host_remote.h"
|
| +#include "cc/proto/compositor_message.pb.h"
|
| +#include "cc/test/fake_layer_tree_host.h"
|
| +#include "cc/test/fake_layer_tree_host_client.h"
|
| +#include "cc/test/fake_remote_compositor_bridge.h"
|
| +#include "cc/test/remote_client_layer_factory.h"
|
| +#include "cc/test/stub_layer_tree_host_client.h"
|
| +#include "cc/test/test_task_graph_runner.h"
|
| +#include "cc/trees/layer_tree_host_common.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +
|
| +namespace cc {
|
| +namespace {
|
| +
|
| +#define EXPECT_LAYERS_EQ(engine_layer_id, client_layer) \
|
| + EXPECT_EQ( \
|
| + compositor_state_deserializer_->GetLayerForEngineId(engine_layer_id), \
|
| + client_layer);
|
| +
|
| +class RemoteCompositorBridgeForTest : public FakeRemoteCompositorBridge {
|
| + public:
|
| + using ProtoFrameCallback = base::Callback<void(
|
| + std::unique_ptr<CompositorProtoState> compositor_proto_state)>;
|
| +
|
| + RemoteCompositorBridgeForTest(
|
| + scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
|
| + ProtoFrameCallback proto_frame_callback)
|
| + : FakeRemoteCompositorBridge(main_task_runner),
|
| + proto_frame_callback_(proto_frame_callback) {}
|
| +
|
| + ~RemoteCompositorBridgeForTest() override = default;
|
| +
|
| + void ProcessCompositorStateUpdate(
|
| + std::unique_ptr<CompositorProtoState> compositor_proto_state) override {
|
| + proto_frame_callback_.Run(std::move(compositor_proto_state));
|
| + }
|
| +
|
| + private:
|
| + ProtoFrameCallback proto_frame_callback_;
|
| +};
|
| +
|
| +class CompositorStateDeserializerTest
|
| + : public testing::Test,
|
| + public CompositorStateDeserializerClient {
|
| + public:
|
| + void SetUp() override {
|
| + scoped_refptr<base::SingleThreadTaskRunner> main_task_runner =
|
| + base::ThreadTaskRunnerHandle::Get();
|
| +
|
| + // Engine side setup.
|
| + LayerTreeHostRemote::InitParams params;
|
| + params.client = &layer_tree_host_client_remote_;
|
| + params.main_task_runner = main_task_runner;
|
| + params.animation_host = AnimationHost::CreateMainInstance();
|
| + params.remote_compositor_bridge =
|
| + base::MakeUnique<RemoteCompositorBridgeForTest>(
|
| + main_task_runner,
|
| + base::Bind(
|
| + &CompositorStateDeserializerTest::ProcessCompositorStateUpdate,
|
| + base::Unretained(this)));
|
| + LayerTreeSettings settings;
|
| + params.settings = &settings;
|
| +
|
| + layer_tree_host_remote_ = base::MakeUnique<LayerTreeHostRemote>(¶ms);
|
| +
|
| + // Client side setup.
|
| + layer_tree_host_in_process_ = FakeLayerTreeHost::Create(
|
| + &layer_tree_host_client_client_, &task_graph_runner_);
|
| + compositor_state_deserializer_ =
|
| + base::MakeUnique<CompositorStateDeserializer>(
|
| + layer_tree_host_in_process_.get(),
|
| + base::Bind(&CompositorStateDeserializerTest::LayerScrolled,
|
| + base::Unretained(this)),
|
| + this);
|
| + }
|
| +
|
| + void TearDown() override {
|
| + layer_tree_host_remote_ = nullptr;
|
| + compositor_state_deserializer_ = nullptr;
|
| + layer_tree_host_in_process_ = nullptr;
|
| + }
|
| +
|
| + void ProcessCompositorStateUpdate(
|
| + std::unique_ptr<CompositorProtoState> compositor_proto_state) {
|
| + // Immediately deserialize the state update.
|
| + compositor_state_deserializer_->DeserializeCompositorUpdate(
|
| + compositor_proto_state->compositor_message->layer_tree_host());
|
| + }
|
| +
|
| + // CompositorStateDeserializer implementation.
|
| + bool ShouldRetainClientScroll(int engine_layer_id,
|
| + const gfx::ScrollOffset& new_offset) override {
|
| + return should_retain_client_scroll_;
|
| + }
|
| + bool ShouldRetainClientPageScale(float new_page_scale) override {
|
| + return should_retain_client_scale_;
|
| + }
|
| +
|
| + void LayerScrolled(int engine_layer_id) {}
|
| +
|
| + void VerifyTreesAreIdentical() {
|
| + LayerTree* engine_layer_tree = layer_tree_host_remote_->GetLayerTree();
|
| + LayerTree* client_layer_tree = layer_tree_host_in_process_->GetLayerTree();
|
| +
|
| + if (engine_layer_tree->root_layer()) {
|
| + LayerTreeHostCommon::CallFunctionForEveryLayer(
|
| + engine_layer_tree, [this](Layer* engine_layer) {
|
| + VerifyLayersAreIdentical(
|
| + engine_layer,
|
| + compositor_state_deserializer_->GetLayerForEngineId(
|
| + engine_layer->id()));
|
| + });
|
| + } else {
|
| + EXPECT_EQ(layer_tree_host_in_process_->GetLayerTree()->root_layer(),
|
| + nullptr);
|
| + }
|
| +
|
| + // Viewport layers.
|
| + // Overscroll Elasticty Layer.
|
| + Layer* client_overscroll_elasticity_layer =
|
| + client_layer_tree->overscroll_elasticity_layer();
|
| + if (engine_layer_tree->overscroll_elasticity_layer()) {
|
| + int engine_overscroll_elasticity_layer_id =
|
| + engine_layer_tree->overscroll_elasticity_layer()->id();
|
| +
|
| + EXPECT_LAYERS_EQ(engine_overscroll_elasticity_layer_id,
|
| + client_overscroll_elasticity_layer);
|
| + } else {
|
| + EXPECT_EQ(client_overscroll_elasticity_layer, nullptr);
|
| + }
|
| +
|
| + // PageScale Layer.
|
| + Layer* client_page_scale_layer = client_layer_tree->page_scale_layer();
|
| + if (engine_layer_tree->page_scale_layer()) {
|
| + int engine_page_scale_layer_id =
|
| + engine_layer_tree->page_scale_layer()->id();
|
| +
|
| + EXPECT_LAYERS_EQ(engine_page_scale_layer_id, client_page_scale_layer);
|
| + } else {
|
| + EXPECT_EQ(client_page_scale_layer, nullptr);
|
| + }
|
| +
|
| + // InnerViewportScroll Layer.
|
| + Layer* client_inner_viewport_layer =
|
| + client_layer_tree->inner_viewport_scroll_layer();
|
| + if (engine_layer_tree->inner_viewport_scroll_layer()) {
|
| + int engine_inner_viewport_layer_id =
|
| + engine_layer_tree->inner_viewport_scroll_layer()->id();
|
| +
|
| + EXPECT_LAYERS_EQ(engine_inner_viewport_layer_id,
|
| + client_inner_viewport_layer);
|
| + } else {
|
| + EXPECT_EQ(client_inner_viewport_layer, nullptr);
|
| + }
|
| +
|
| + // OuterViewportScroll Layer.
|
| + Layer* client_outer_viewport_layer =
|
| + client_layer_tree->outer_viewport_scroll_layer();
|
| + if (engine_layer_tree->outer_viewport_scroll_layer()) {
|
| + int engine_outer_viewport_layer_id =
|
| + engine_layer_tree->outer_viewport_scroll_layer()->id();
|
| +
|
| + EXPECT_LAYERS_EQ(engine_outer_viewport_layer_id,
|
| + client_outer_viewport_layer);
|
| + } else {
|
| + EXPECT_EQ(client_outer_viewport_layer, nullptr);
|
| + }
|
| + }
|
| +
|
| + void VerifyLayersAreIdentical(Layer* engine_layer, Layer* client_layer) {
|
| + ASSERT_NE(client_layer, nullptr);
|
| +
|
| + LayerTree* client_layer_tree = layer_tree_host_in_process_->GetLayerTree();
|
| + EXPECT_EQ(client_layer_tree, client_layer->GetLayerTree());
|
| +
|
| + // Parent.
|
| + if (engine_layer->parent()) {
|
| + int engine_parent_id = engine_layer->parent()->id();
|
| + EXPECT_LAYERS_EQ(engine_parent_id, client_layer->parent());
|
| + } else {
|
| + EXPECT_EQ(client_layer->parent(), nullptr);
|
| + }
|
| +
|
| + // Mask Layers.
|
| + if (engine_layer->mask_layer()) {
|
| + int engine_mask_layer_id = engine_layer->mask_layer()->id();
|
| + EXPECT_LAYERS_EQ(engine_mask_layer_id, client_layer->mask_layer());
|
| + } else {
|
| + EXPECT_EQ(client_layer->mask_layer(), nullptr);
|
| + }
|
| +
|
| + // Scroll parent.
|
| + if (engine_layer->scroll_parent()) {
|
| + int engine_scroll_parent_id = engine_layer->scroll_parent()->id();
|
| + EXPECT_LAYERS_EQ(engine_scroll_parent_id, client_layer->scroll_parent());
|
| + } else {
|
| + EXPECT_EQ(client_layer->scroll_parent(), nullptr);
|
| + }
|
| +
|
| + // Clip parent.
|
| + if (engine_layer->clip_parent()) {
|
| + int engine_clip_parent_id = engine_layer->clip_parent()->id();
|
| + EXPECT_LAYERS_EQ(engine_clip_parent_id, client_layer->clip_parent());
|
| + } else {
|
| + EXPECT_EQ(client_layer->clip_parent(), nullptr);
|
| + }
|
| +
|
| + // Scroll-clip layer.
|
| + if (engine_layer->scroll_clip_layer()) {
|
| + int scroll_clip_id = engine_layer->scroll_clip_layer()->id();
|
| + EXPECT_LAYERS_EQ(scroll_clip_id, client_layer->scroll_clip_layer());
|
| + } else {
|
| + EXPECT_EQ(client_layer->scroll_clip_layer(), nullptr);
|
| + }
|
| + }
|
| +
|
| + // Engine setup.
|
| + std::unique_ptr<LayerTreeHostRemote> layer_tree_host_remote_;
|
| + StubLayerTreeHostClient layer_tree_host_client_remote_;
|
| +
|
| + // Client setup.
|
| + std::unique_ptr<FakeLayerTreeHost> layer_tree_host_in_process_;
|
| + std::unique_ptr<CompositorStateDeserializer> compositor_state_deserializer_;
|
| + FakeLayerTreeHostClient layer_tree_host_client_client_;
|
| + TestTaskGraphRunner task_graph_runner_;
|
| +
|
| + bool should_retain_client_scroll_ = false;
|
| + bool should_retain_client_scale_ = false;
|
| +};
|
| +
|
| +TEST_F(CompositorStateDeserializerTest, BasicSync) {
|
| + // Set up a tree with a single node.
|
| + scoped_refptr<Layer> root_layer = Layer::Create();
|
| + layer_tree_host_remote_->GetLayerTree()->SetRootLayer(root_layer);
|
| +
|
| + // Synchronize State and verify.
|
| + base::RunLoop().RunUntilIdle();
|
| + VerifyTreesAreIdentical();
|
| +
|
| + // Swap the root layer.
|
| + scoped_refptr<Layer> new_root_layer = Layer::Create();
|
| + new_root_layer->AddChild(Layer::Create());
|
| + new_root_layer->AddChild(Layer::Create());
|
| + layer_tree_host_remote_->GetLayerTree()->SetRootLayer(new_root_layer);
|
| +
|
| + // Synchronize State and verify.
|
| + base::RunLoop().RunUntilIdle();
|
| + VerifyTreesAreIdentical();
|
| + // Verify that we are no longer tracking the destroyed layer on the client.
|
| + EXPECT_EQ(
|
| + compositor_state_deserializer_->GetLayerForEngineId(root_layer->id()),
|
| + nullptr);
|
| +
|
| + // Remove the root layer to change to a null tree.
|
| + layer_tree_host_remote_->GetLayerTree()->SetRootLayer(nullptr);
|
| +
|
| + // Synchronize State and verify.
|
| + base::RunLoop().RunUntilIdle();
|
| + VerifyTreesAreIdentical();
|
| +}
|
| +
|
| +TEST_F(CompositorStateDeserializerTest, ViewportLayers) {
|
| + scoped_refptr<Layer> root_layer = Layer::Create();
|
| + layer_tree_host_remote_->GetLayerTree()->SetRootLayer(root_layer);
|
| +
|
| + scoped_refptr<Layer> overscroll_elasticity_layer = Layer::Create();
|
| + scoped_refptr<Layer> inner_viewport_scroll_layer = Layer::Create();
|
| + scoped_refptr<Layer> outer_viewport_scroll_layer = Layer::Create();
|
| + scoped_refptr<Layer> page_scale_layer = Layer::Create();
|
| + layer_tree_host_remote_->GetLayerTree()->RegisterViewportLayers(
|
| + overscroll_elasticity_layer, page_scale_layer,
|
| + inner_viewport_scroll_layer, outer_viewport_scroll_layer);
|
| +
|
| + root_layer->AddChild(overscroll_elasticity_layer);
|
| + overscroll_elasticity_layer->AddChild(page_scale_layer);
|
| + page_scale_layer->AddChild(inner_viewport_scroll_layer);
|
| + inner_viewport_scroll_layer->AddChild(outer_viewport_scroll_layer);
|
| +
|
| + // Synchronize State and verify.
|
| + base::RunLoop().RunUntilIdle();
|
| + VerifyTreesAreIdentical();
|
| +}
|
| +
|
| +TEST_F(CompositorStateDeserializerTest, ScrollClipAndMaskLayers) {
|
| + /* root -- A---C---D
|
| + / | \
|
| + / | E(MaskLayer)
|
| + / ------B */
|
| + scoped_refptr<Layer> root_layer = Layer::Create();
|
| + layer_tree_host_remote_->GetLayerTree()->SetRootLayer(root_layer);
|
| +
|
| + scoped_refptr<Layer> layer_a = Layer::Create();
|
| + scoped_refptr<Layer> layer_b = Layer::Create();
|
| + scoped_refptr<Layer> layer_c = Layer::Create();
|
| + scoped_refptr<Layer> layer_d = Layer::Create();
|
| + scoped_refptr<Layer> layer_e = Layer::Create();
|
| +
|
| + root_layer->AddChild(layer_a);
|
| + root_layer->AddChild(layer_b);
|
| + layer_a->AddChild(layer_c);
|
| + layer_c->AddChild(layer_d);
|
| +
|
| + layer_a->SetMaskLayer(layer_e.get());
|
| + layer_c->SetScrollParent(layer_b.get());
|
| + layer_c->SetScrollClipLayerId(root_layer->id());
|
| + layer_d->SetClipParent(layer_a.get());
|
| +
|
| + // Synchronize State and verify.
|
| + base::RunLoop().RunUntilIdle();
|
| + VerifyTreesAreIdentical();
|
| +}
|
| +
|
| +TEST_F(CompositorStateDeserializerTest, ReconcileScrollAndScale) {
|
| + scoped_refptr<Layer> root_layer = Layer::Create();
|
| + layer_tree_host_remote_->GetLayerTree()->SetRootLayer(root_layer);
|
| +
|
| + // Set scroll offset.
|
| + scoped_refptr<Layer> scroll_layer = Layer::Create();
|
| + root_layer->AddChild(scroll_layer);
|
| + gfx::ScrollOffset engine_offset(4, 3);
|
| + scroll_layer->SetScrollOffset(engine_offset);
|
| +
|
| + // Set page scale.
|
| + float engine_page_scale = 0.5f;
|
| + layer_tree_host_remote_->GetLayerTree()->SetPageScaleFactorAndLimits(
|
| + engine_page_scale, 1.0, 1.0);
|
| +
|
| + // Synchronize State and verify that the engine values are used.
|
| + base::RunLoop().RunUntilIdle();
|
| + VerifyTreesAreIdentical();
|
| +
|
| + EXPECT_EQ(engine_page_scale,
|
| + layer_tree_host_in_process_->GetLayerTree()->page_scale_factor());
|
| + EXPECT_EQ(engine_offset, compositor_state_deserializer_
|
| + ->GetLayerForEngineId(scroll_layer->id())
|
| + ->scroll_offset());
|
| +
|
| + // Now reset the scroll offset and page scale and force-retain the client
|
| + // values.
|
| + gfx::ScrollOffset new_engine_offset(2, 2);
|
| + scroll_layer->SetScrollOffset(new_engine_offset);
|
| + float new_engine_page_scale = 0.8f;
|
| + layer_tree_host_remote_->GetLayerTree()->SetPageScaleFactorAndLimits(
|
| + new_engine_page_scale, 1.0, 1.0);
|
| + should_retain_client_scroll_ = true;
|
| + should_retain_client_scale_ = true;
|
| +
|
| + // Synchronize State and verify that the client values are retained.
|
| + base::RunLoop().RunUntilIdle();
|
| + VerifyTreesAreIdentical();
|
| +
|
| + EXPECT_EQ(engine_page_scale,
|
| + layer_tree_host_in_process_->GetLayerTree()->page_scale_factor());
|
| + EXPECT_EQ(engine_offset, compositor_state_deserializer_
|
| + ->GetLayerForEngineId(scroll_layer->id())
|
| + ->scroll_offset());
|
| +}
|
| +
|
| +TEST_F(CompositorStateDeserializerTest, PropertyTreesAreIdentical) {
|
| + // Override the LayerFactory. This is necessary to ensure the layer ids
|
| + // tracked in PropertyTrees on the engine and client are identical.
|
| + compositor_state_deserializer_->SetLayerFactoryForTesting(
|
| + base::MakeUnique<RemoteClientLayerFactory>());
|
| +
|
| + scoped_refptr<Layer> root_layer = Layer::Create();
|
| + root_layer->SetBounds(gfx::Size(10, 10));
|
| + layer_tree_host_remote_->GetLayerTree()->SetRootLayer(root_layer);
|
| +
|
| + scoped_refptr<Layer> child1 = Layer::Create();
|
| + root_layer->AddChild(child1);
|
| + gfx::Transform transform;
|
| + transform.Translate(gfx::Vector2dF(5, 4));
|
| + child1->SetTransform(transform);
|
| + child1->SetMasksToBounds(true);
|
| +
|
| + scoped_refptr<Layer> child2 = Layer::Create();
|
| + root_layer->AddChild(child2);
|
| + child2->SetBounds(gfx::Size(5, 5));
|
| + child2->SetScrollOffset(gfx::ScrollOffset(3, 4));
|
| + child2->SetScrollParent(child1.get());
|
| + child2->SetUserScrollable(true, true);
|
| +
|
| + scoped_refptr<Layer> grandchild11 = Layer::Create();
|
| + child1->AddChild(grandchild11);
|
| + grandchild11->SetClipParent(root_layer.get());
|
| +
|
| + scoped_refptr<Layer> grandchild21 = Layer::Create();
|
| + child2->AddChild(grandchild21);
|
| + grandchild21->SetScrollClipLayerId(child1->id());
|
| + grandchild21->SetOpacity(0.5);
|
| +
|
| + // Synchronize State and verify.
|
| + base::RunLoop().RunUntilIdle();
|
| + VerifyTreesAreIdentical();
|
| + EXPECT_EQ(root_layer->id(), layer_tree_host_in_process_->root_layer()->id());
|
| +
|
| + // Sanity test to ensure that the PropertyTrees generated from the Layers on
|
| + // the client and engine are identical.
|
| + layer_tree_host_remote_->GetLayerTree()->BuildPropertyTreesForTesting();
|
| + PropertyTrees* engine_property_trees =
|
| + layer_tree_host_remote_->GetLayerTree()->property_trees();
|
| +
|
| + layer_tree_host_in_process_->BuildPropertyTreesForTesting();
|
| + PropertyTrees* client_property_trees =
|
| + layer_tree_host_in_process_->property_trees();
|
| +
|
| + EXPECT_EQ(*engine_property_trees, *client_property_trees);
|
| +}
|
| +
|
| +} // namespace
|
| +} // namespace cc
|
|
|