blob: 60cc595e48e2b53f2691347816eb1324f99f5c49 [file] [log] [blame]
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/paint_preview/common/paint_preview_tracker.h"
#include "base/containers/flat_map.h"
#include "base/memory/raw_ptr.h"
#include "base/unguessable_token.h"
#include "components/paint_preview/common/serial_utils.h"
#include "skia/ext/font_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkPicture.h"
#include "third_party/skia/include/core/SkPictureRecorder.h"
#include "third_party/skia/include/core/SkRect.h"
#include "third_party/skia/include/core/SkRefCnt.h"
#include "third_party/skia/include/core/SkTextBlob.h"
#include "ui/gfx/geometry/rect.h"
namespace paint_preview {
namespace {
struct TestContext {
raw_ptr<const gfx::Rect> rect;
bool was_called;
};
// A test canvas for checking that the pictures drawn to it have the cull rect
// we expect them to.
class ExpectSubframeCanvas : public SkCanvas {
public:
void onDrawPicture(const SkPicture* picture,
const SkMatrix*,
const SkPaint*) override {
drawn_pictures_.insert({picture->uniqueID(), picture->cullRect()});
}
void ExpectHasPicture(uint32_t expected_picture_id,
const gfx::Rect& expected_bounds) {
auto it = drawn_pictures_.find(expected_picture_id);
if (it == drawn_pictures_.end()) {
ADD_FAILURE() << "Picture ID was not recorded.";
return;
}
SkIRect rect = it->second.round();
EXPECT_EQ(rect.x(), expected_bounds.x());
EXPECT_EQ(rect.y(), expected_bounds.y());
EXPECT_EQ(rect.width(), expected_bounds.width());
EXPECT_EQ(rect.height(), expected_bounds.height());
}
private:
// Map of picture id to expected bounds of pictures drawn into this canvas.
base::flat_map<uint32_t, SkRect> drawn_pictures_;
};
} // namespace
TEST(PaintPreviewTrackerTest, TestGetters) {
const base::UnguessableToken kDocToken = base::UnguessableToken::Create();
const base::UnguessableToken kEmbeddingToken =
base::UnguessableToken::Create();
PaintPreviewTracker tracker(kDocToken, kEmbeddingToken, true);
EXPECT_EQ(tracker.Guid(), kDocToken);
EXPECT_EQ(tracker.EmbeddingToken(), kEmbeddingToken);
EXPECT_TRUE(tracker.IsMainFrame());
}
TEST(PaintPreviewTrackerTest, TestRemoteFramePlaceholderPicture) {
const base::UnguessableToken kDocToken = base::UnguessableToken::Create();
const base::UnguessableToken kEmbeddingToken =
base::UnguessableToken::Create();
PaintPreviewTracker tracker(kDocToken, kEmbeddingToken, true);
const base::UnguessableToken kEmbeddingTokenChild =
base::UnguessableToken::Create();
gfx::Rect rect(50, 40, 30, 20);
uint32_t content_id =
tracker.CreateContentForRemoteFrame(rect, kEmbeddingTokenChild);
PictureSerializationContext* context =
tracker.GetPictureSerializationContext();
EXPECT_TRUE(context->content_id_to_embedding_token.count(content_id));
EXPECT_EQ(context->content_id_to_embedding_token[content_id],
kEmbeddingTokenChild);
ExpectSubframeCanvas canvas;
tracker.CustomDataToSkPictureCallback(&canvas, content_id);
canvas.ExpectHasPicture(content_id, rect);
}
TEST(PaintPreviewTrackerTest, TestGlyphRunList) {
const base::UnguessableToken kEmbeddingToken =
base::UnguessableToken::Create();
PaintPreviewTracker tracker(base::UnguessableToken::Create(), kEmbeddingToken,
true);
std::string unichars = "abc";
auto typeface = skia::DefaultTypeface();
SkFont font(typeface);
auto blob = SkTextBlob::MakeFromString(unichars.c_str(), font);
tracker.AddGlyphs(blob.get());
auto* usage_map = tracker.GetTypefaceUsageMap();
EXPECT_TRUE(usage_map->count(typeface->uniqueID()));
EXPECT_TRUE(
(*usage_map)[typeface->uniqueID()]->IsSet(typeface->unicharToGlyph('a')));
EXPECT_TRUE(
(*usage_map)[typeface->uniqueID()]->IsSet(typeface->unicharToGlyph('b')));
EXPECT_TRUE(
(*usage_map)[typeface->uniqueID()]->IsSet(typeface->unicharToGlyph('c')));
}
TEST(PaintPreviewTrackerTest, TestAnnotateLinks) {
const base::UnguessableToken kEmbeddingToken =
base::UnguessableToken::Create();
PaintPreviewTracker tracker(base::UnguessableToken::Create(), kEmbeddingToken,
true);
const GURL url_1("https://www.chromium.org");
const auto rect_1 = SkRect::MakeXYWH(10, 20, 30, 40);
tracker.AnnotateLink(url_1, rect_1);
const GURL url_2("https://www.w3.org");
const auto rect_2 = SkRect::MakeXYWH(15, 25, 35, 45);
tracker.AnnotateLink(url_2, rect_2);
ASSERT_EQ(tracker.GetLinks().size(), 2U);
EXPECT_EQ(tracker.GetLinks()[0]->url, url_1);
EXPECT_EQ(tracker.GetLinks()[0]->rect.width(), rect_1.width());
EXPECT_EQ(tracker.GetLinks()[0]->rect.height(), rect_1.height());
EXPECT_EQ(tracker.GetLinks()[0]->rect.x(), rect_1.x());
EXPECT_EQ(tracker.GetLinks()[0]->rect.y(), rect_1.y());
EXPECT_EQ(tracker.GetLinks()[1]->url, url_2);
EXPECT_EQ(tracker.GetLinks()[1]->rect.width(), rect_2.width());
EXPECT_EQ(tracker.GetLinks()[1]->rect.height(), rect_2.height());
EXPECT_EQ(tracker.GetLinks()[1]->rect.x(), rect_2.x());
EXPECT_EQ(tracker.GetLinks()[1]->rect.y(), rect_2.y());
}
TEST(PaintPreviewTrackerTest, TestAnnotateAndMoveLinks) {
const base::UnguessableToken kEmbeddingToken =
base::UnguessableToken::Create();
PaintPreviewTracker tracker(base::UnguessableToken::Create(), kEmbeddingToken,
true);
const GURL url_1("https://www.chromium.org");
const auto rect_1 = SkRect::MakeXYWH(10, 20, 30, 40);
tracker.AnnotateLink(url_1, rect_1);
const GURL url_2("https://www.w3.org");
const auto rect_2 = SkRect::MakeXYWH(15, 25, 35, 45);
tracker.AnnotateLink(url_2, rect_2);
std::vector<mojom::LinkDataPtr> links;
tracker.MoveLinks(&links);
ASSERT_EQ(tracker.GetLinks().size(), 0U);
ASSERT_EQ(links.size(), 2U);
EXPECT_EQ(links[0]->url, url_1);
EXPECT_EQ(links[0]->rect.width(), rect_1.width());
EXPECT_EQ(links[0]->rect.height(), rect_1.height());
EXPECT_EQ(links[0]->rect.x(), rect_1.x());
EXPECT_EQ(links[0]->rect.y(), rect_1.y());
EXPECT_EQ(links[1]->url, url_2);
EXPECT_EQ(links[1]->rect.width(), rect_2.width());
EXPECT_EQ(links[1]->rect.height(), rect_2.height());
EXPECT_EQ(links[1]->rect.x(), rect_2.x());
EXPECT_EQ(links[1]->rect.y(), rect_2.y());
}
TEST(PaintPreviewTrackerTest, AnnotateLinksWithTransform) {
const base::UnguessableToken kEmbeddingToken =
base::UnguessableToken::Create();
PaintPreviewTracker tracker(base::UnguessableToken::Create(), kEmbeddingToken,
true);
const GURL url("http://www.chromium.org");
const auto rect = SkRect::MakeXYWH(10, 20, 30, 40);
tracker.AnnotateLink(url, rect);
std::vector<mojom::LinkDataPtr> links;
tracker.MoveLinks(&links);
ASSERT_EQ(links.size(), 1U);
EXPECT_EQ(links[0]->url, url);
EXPECT_EQ(links[0]->rect.width(), rect.width());
EXPECT_EQ(links[0]->rect.height(), rect.height());
EXPECT_EQ(links[0]->rect.x(), rect.x());
EXPECT_EQ(links[0]->rect.y(), rect.y());
tracker.Save();
tracker.Scale(2, 4);
tracker.AnnotateLink(url, rect);
links.clear();
tracker.MoveLinks(&links);
EXPECT_EQ(links[0]->url, url);
EXPECT_EQ(links[0]->rect.width(), rect.width() * 2);
EXPECT_EQ(links[0]->rect.height(), rect.height() * 4);
EXPECT_EQ(links[0]->rect.x(), rect.x() * 2);
EXPECT_EQ(links[0]->rect.y(), rect.y() * 4);
tracker.Translate(10, 20);
tracker.AnnotateLink(url, rect);
links.clear();
tracker.MoveLinks(&links);
EXPECT_EQ(links[0]->url, url);
EXPECT_EQ(links[0]->rect.width(), rect.width() * 2);
EXPECT_EQ(links[0]->rect.height(), rect.height() * 4);
EXPECT_EQ(links[0]->rect.x(), (10 + rect.x()) * 2);
EXPECT_EQ(links[0]->rect.y(), (20 + rect.y()) * 4);
tracker.Restore();
links.clear();
tracker.AnnotateLink(url, rect);
tracker.MoveLinks(&links);
ASSERT_EQ(links.size(), 1U);
EXPECT_EQ(links[0]->url, url);
EXPECT_EQ(links[0]->rect.width(), rect.width());
EXPECT_EQ(links[0]->rect.height(), rect.height());
EXPECT_EQ(links[0]->rect.x(), rect.x());
EXPECT_EQ(links[0]->rect.y(), rect.y());
tracker.Concat(SkMatrix::Translate(30, 100));
links.clear();
tracker.AnnotateLink(url, rect);
tracker.MoveLinks(&links);
ASSERT_EQ(links.size(), 1U);
EXPECT_EQ(links[0]->url, url);
EXPECT_EQ(links[0]->rect.width(), rect.width());
EXPECT_EQ(links[0]->rect.height(), rect.height());
EXPECT_EQ(links[0]->rect.x(), rect.x() + 30);
EXPECT_EQ(links[0]->rect.y(), rect.y() + 100);
tracker.Rotate(30);
links.clear();
tracker.AnnotateLink(url, rect);
tracker.MoveLinks(&links);
ASSERT_EQ(links.size(), 1U);
EXPECT_EQ(links[0]->url, url);
EXPECT_EQ(links[0]->rect.width(), 45);
EXPECT_EQ(links[0]->rect.height(), 49);
EXPECT_EQ(links[0]->rect.x(), 8);
EXPECT_EQ(links[0]->rect.y(), 122);
// no-op (ensure this doesn't crash).
tracker.Restore();
}
} // namespace paint_preview