blob: eb9c4a2ce54099881c89f1d45325eb1fc912da33 [file] [log] [blame]
// Copyright 2019 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 "cc/trees/layer_tree_host.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/transform_node.h"
namespace cc {
namespace {
class FakeTextHolder {
public:
FakeTextHolder(const std::string& text, const gfx::Rect& rect, NodeId node_id)
: text_(text), rect_(rect), node_id_(node_id) {}
std::string text() const { return text_; }
gfx::Rect rect() const { return rect_; }
NodeId node_id() const { return node_id_; }
private:
std::string text_;
gfx::Rect rect_;
NodeId node_id_;
};
class FakeCaptureContentLayerClient : public FakeContentLayerClient {
public:
void addTextHolder(const FakeTextHolder& holder) {
holders_.push_back(holder);
}
scoped_refptr<DisplayItemList> PaintContentsToDisplayList() override {
auto display_list = base::MakeRefCounted<DisplayItemList>();
for (auto& holder : holders_) {
display_list->StartPaint();
display_list->push<DrawTextBlobOp>(
SkTextBlob::MakeFromString(holder.text().data(), SkFont()),
static_cast<float>(holder.rect().x()),
static_cast<float>(holder.rect().y()), holder.node_id(),
PaintFlags());
display_list->EndPaintOfUnpaired(holder.rect());
}
display_list->Finalize();
return display_list;
}
private:
std::vector<const FakeTextHolder> holders_;
};
// These tests are for LayerTreeHost::CaptureContent().
class LayerTreeHostCaptureContentTest : public LayerTreeTest {
public:
~LayerTreeHostCaptureContentTest() override = default;
protected:
LayerTreeHostCaptureContentTest() : device_bounds_(10, 10) {}
void BeginTest() override { PostSetNeedsCommitToMainThread(); }
void DidCommit() override { PostCaptureContentToMainThread(); }
void SetupRootPictureLayer(const gfx::Size& size) {
scoped_refptr<Layer> root = Layer::Create();
root->SetBounds(size);
client_.set_bounds(size);
root_picture_layer_ = FakePictureLayer::Create(&client_);
root_picture_layer_->SetBounds(size);
root->AddChild(root_picture_layer_);
layer_tree_host()->SetRootLayer(root);
layer_tree_host()->SetVisualDeviceViewportIntersectionRect(
gfx::Rect(device_bounds_));
}
void VerifyCapturedContent(std::vector<FakeTextHolder>* expected_result) {
EXPECT_EQ(expected_result->size(), captured_content_.size());
size_t expected_left_result = expected_result->size();
for (auto& c : captured_content_) {
for (auto it = expected_result->begin(); it != expected_result->end();
++it) {
if (it->node_id() == c.node_id) {
expected_result->erase(it);
break;
}
}
EXPECT_EQ(--expected_left_result, expected_result->size());
}
}
FakeCaptureContentLayerClient client_;
private:
void PostCaptureContentToMainThread() {
MainThreadTaskRunner()->PostTask(
FROM_HERE,
base::BindOnce(&LayerTreeHostCaptureContentTest::CaptureContent,
weak_factory_.GetWeakPtr()));
}
void CaptureContent() {
captured_content_.clear();
layer_tree_host()->CaptureContent(&captured_content_);
EndTest();
}
scoped_refptr<FakePictureLayer> root_picture_layer_;
std::vector<NodeInfo> captured_content_;
const gfx::Size device_bounds_;
base::WeakPtrFactory<LayerTreeHostCaptureContentTest> weak_factory_{this};
};
class LayerTreeHostCaptureContentTestBasic
: public LayerTreeHostCaptureContentTest {
protected:
void SetupTextHolders(const gfx::Rect& rect1, const gfx::Rect& rect2) {
text_holder_1_ = std::make_unique<FakeTextHolder>("Text1", rect1, 1);
client_.addTextHolder(*text_holder_1_);
text_holder_2_ = std::make_unique<FakeTextHolder>("Text2", rect2, 2);
client_.addTextHolder(*text_holder_2_);
}
std::unique_ptr<FakeTextHolder> text_holder_1_;
std::unique_ptr<FakeTextHolder> text_holder_2_;
};
// Test that one DrawTextBlobOp is on-screen, another isn't.
class LayerTreeHostCaptureContentTestOneVisible
: public LayerTreeHostCaptureContentTestBasic {
protected:
void SetupTree() override {
// One is visible.
SetupTextHolders(gfx::Rect(0, 0, 5, 5), gfx::Rect(11, 0, 5, 5));
SetupRootPictureLayer(gfx::Size(10, 10));
}
void AfterTest() override {
std::vector<FakeTextHolder> expected_result;
expected_result.push_back(*text_holder_1_);
VerifyCapturedContent(&expected_result);
}
};
SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostCaptureContentTestOneVisible);
// Test that both DrawTextBlobOps are on-screen.
class LayerTreeHostCaptureContentTestTwoVisible
: public LayerTreeHostCaptureContentTestBasic {
protected:
void SetupTree() override {
// One is visible, another is partial visible.
SetupTextHolders(gfx::Rect(0, 0, 5, 5), gfx::Rect(9, 0, 5, 5));
SetupRootPictureLayer(gfx::Size(10, 10));
}
void AfterTest() override {
std::vector<FakeTextHolder> expected_result;
expected_result.push_back(*text_holder_1_);
expected_result.push_back(*text_holder_2_);
VerifyCapturedContent(&expected_result);
}
};
SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostCaptureContentTestTwoVisible);
// Base class for two layers tests.
class LayerTreeHostCaptureContentTestTwoLayers
: public LayerTreeHostCaptureContentTestBasic {
protected:
void SetupTree() override {
SetupTextHolders(gfx::Rect(0, 0, 5, 5), gfx::Rect(5, 5, 5, 5));
SetupRootPictureLayer(gfx::Size(10, 10));
SetupSecondaryPictureLayer(gfx::Size(10, 10));
}
void DidCommit() override {
LayerTreeHostCaptureContentTestBasic::DidCommit();
OnSetupSecondaryLayTransform();
}
virtual void OnSetupSecondaryLayTransform() {}
virtual bool IsSecondaryPictureLayerContentsOpaque() { return true; }
// Setup transform node for secondary picture layer, must be called in
// OnSetupSecondaryLayTransform().
void SetupTransform(const gfx::Vector2dF& translate) {
TransformNode transform_node;
transform_node.local.Translate(translate);
transform_node.id =
layer_tree_host()->property_trees()->transform_tree.Insert(
transform_node, 0);
picture_layer->SetTransformTreeIndex(transform_node.id);
layer_tree_host()->property_trees()->transform_tree.UpdateTransforms(
transform_node.id);
}
void SetupSecondaryPictureLayer(const gfx::Size& size) {
// Add text to layer.
text_holder_21_ =
std::make_unique<FakeTextHolder>("Text21", gfx::Rect(0, 0, 10, 5), 21);
client2_.addTextHolder(*text_holder_21_);
text_holder_22_ =
std::make_unique<FakeTextHolder>("Text22", gfx::Rect(0, 5, 10, 5), 22);
client2_.addTextHolder(*text_holder_22_);
client2_.set_bounds(size);
// Create layer.
picture_layer = FakePictureLayer::Create(&client2_);
picture_layer->SetBounds(size);
picture_layer->SetContentsOpaque(IsSecondaryPictureLayerContentsOpaque());
layer_tree_host()->root_layer()->AddChild(picture_layer);
}
scoped_refptr<FakePictureLayer> picture_layer;
std::unique_ptr<FakeTextHolder> text_holder_21_;
std::unique_ptr<FakeTextHolder> text_holder_22_;
FakeCaptureContentLayerClient client2_;
};
// Test that one layer is within screen, another isn't.
class LayerTreeHostCaptureContentTestOneLayerVisible
: public LayerTreeHostCaptureContentTestTwoLayers {
void OnSetupSecondaryLayTransform() override {
// Moves the layer out of visual port.
SetupTransform(gfx::Vector2dF(0, 10));
}
void AfterTest() override {
std::vector<FakeTextHolder> expected_result;
expected_result.push_back(*text_holder_1_);
expected_result.push_back(*text_holder_2_);
VerifyCapturedContent(&expected_result);
}
};
SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostCaptureContentTestOneLayerVisible);
// Test that the upper layer is partially on-screen, the under layer fully
// occupies the screen, all layer's on-screen content are returned even the
// upper layer is opaque.
class LayerTreeHostCaptureContentTestTwoLayersVisible
: public LayerTreeHostCaptureContentTestTwoLayers {
void OnSetupSecondaryLayTransform() override {
SetupTransform(gfx::Vector2dF(0, 8));
}
void AfterTest() override {
std::vector<FakeTextHolder> expected_result;
expected_result.push_back(*text_holder_1_);
expected_result.push_back(*text_holder_2_);
expected_result.push_back(*text_holder_21_);
VerifyCapturedContent(&expected_result);
}
};
SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostCaptureContentTestTwoLayersVisible);
// Test that the upper layer is transparent, the under layer fully occupies the
// screen, all layer's on-screen content are returned.
class LayerTreeHostCaptureContentTestTwoLayersVisibleAndTransparent
: public LayerTreeHostCaptureContentTestTwoLayersVisible {
bool IsSecondaryPictureLayerContentsOpaque() override { return false; }
void AfterTest() override {
// All 3 TextHolders are returned.
std::vector<FakeTextHolder> expected_result;
expected_result.push_back(*text_holder_1_);
expected_result.push_back(*text_holder_2_);
expected_result.push_back(*text_holder_21_);
VerifyCapturedContent(&expected_result);
}
};
SINGLE_AND_MULTI_THREAD_TEST_F(
LayerTreeHostCaptureContentTestTwoLayersVisibleAndTransparent);
// Test that the upper layer is partially visible, but doesn't overlay screen in
// either direction, the under layer's content will be captured even it is fully
// overlaid by the upper layer.
class LayerTreeHostCaptureContentTestUpperLayerPartialOverlay
: public LayerTreeHostCaptureContentTestTwoLayers {
void OnSetupSecondaryLayTransform() override {
SetupTransform(gfx::Vector2dF(2, 2));
}
void AfterTest() override {
std::vector<FakeTextHolder> expected_result;
expected_result.push_back(*text_holder_1_);
expected_result.push_back(*text_holder_2_);
expected_result.push_back(*text_holder_21_);
expected_result.push_back(*text_holder_22_);
VerifyCapturedContent(&expected_result);
}
};
SINGLE_AND_MULTI_THREAD_TEST_F(
LayerTreeHostCaptureContentTestUpperLayerPartialOverlay);
} // namespace
} // namespace cc