blob: 1a37ba23a22cc980e15d5402fc37c52647575c07 [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 TextHolder {
public:
FakeTextHolder(const std::string& text, const gfx::Rect& rect)
: text_(text), rect_(rect) {}
std::string text() const { return text_; }
gfx::Rect rect() const { return rect_; }
protected:
~FakeTextHolder() override = default;
private:
std::string text_;
gfx::Rect rect_;
};
class FakeCaptureContentLayerClient : public FakeContentLayerClient {
public:
void addTextHolder(scoped_refptr<FakeTextHolder> holder) {
holders_.push_back(holder);
}
scoped_refptr<DisplayItemList> PaintContentsToDisplayList(
PaintingControlSetting painting_control) override {
auto display_list = base::MakeRefCounted<DisplayItemList>();
for (auto holder : holders_) {
display_list->StartPaint();
display_list->push<DrawTextBlobOp>(
SkTextBlob::MakeFromString(holder->text().data(), SkFont()),
holder->rect().x(), holder->rect().y(), PaintFlags(),
NodeHolder(holder));
display_list->EndPaintOfUnpaired(holder->rect());
}
display_list->Finalize();
return display_list;
}
private:
std::vector<scoped_refptr<FakeTextHolder>> holders_;
};
// These tests are for LayerTreeHost::CaptureContent().
class LayerTreeHostCaptureContentTest : public LayerTreeTest {
public:
~LayerTreeHostCaptureContentTest() override = default;
protected:
LayerTreeHostCaptureContentTest()
: device_bounds_(10, 10), weak_factory_(this) {}
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()->SetViewportVisibleRect(gfx::Rect(device_bounds_));
}
void VerifyCapturedContent(
std::vector<scoped_refptr<FakeTextHolder>>* expected_result) {
EXPECT_EQ(expected_result->size(), captured_content_.size());
size_t expected_left_result = expected_result->size();
for (auto c : captured_content_) {
EXPECT_EQ(c.tag, NodeHolder::TEXT_HOLDER);
for (auto it = expected_result->begin(); it != expected_result->end();
++it) {
if (it->get() == c.text_holder.get()) {
EXPECT_EQ(static_cast<FakeTextHolder*>(c.text_holder.get())->text(),
it->get()->text());
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<NodeHolder> captured_content_;
const gfx::Size device_bounds_;
base::WeakPtrFactory<LayerTreeHostCaptureContentTest> weak_factory_;
};
class LayerTreeHostCaptureContentTestBasic
: public LayerTreeHostCaptureContentTest {
protected:
void SetupTextHolders(const gfx::Rect& rect1, const gfx::Rect& rect2) {
text_holder_1_ = base::MakeRefCounted<FakeTextHolder>("Text1", rect1);
client_.addTextHolder(text_holder_1_);
text_holder_2_ = base::MakeRefCounted<FakeTextHolder>("Text2", rect2);
client_.addTextHolder(text_holder_2_);
}
scoped_refptr<FakeTextHolder> text_holder_1_;
scoped_refptr<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<scoped_refptr<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<scoped_refptr<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.source_node_id = 0;
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_ =
base::MakeRefCounted<FakeTextHolder>("Text21", gfx::Rect(0, 0, 10, 5));
client2_.addTextHolder(text_holder_21_);
text_holder_22_ =
base::MakeRefCounted<FakeTextHolder>("Text22", gfx::Rect(0, 5, 10, 5));
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;
scoped_refptr<FakeTextHolder> text_holder_21_;
scoped_refptr<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<scoped_refptr<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<scoped_refptr<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<scoped_refptr<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<scoped_refptr<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