Commit 55f96bee authored by ckitagawa's avatar ckitagawa Committed by Commit Bot

[Paint Preview] Hit Tester

This CL implements a basic hit testing system for finding links
associated with rects. An instance of the Hit Tester will exist for each
frame to address stacking.

This may return multiple links per query. In such cases, it is up to
the caller to decide which link if any to resolve.

Bug: 1012891
Change-Id: I772ebecae7a7403228e6c50cdc499c1ed7690fcd
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1849209
Commit-Queue: Calder Kitagawa <ckitagawa@chromium.org>
Reviewed-by: default avatarIan Vollick <vollick@chromium.org>
Reviewed-by: default avatarvmpstr <vmpstr@chromium.org>
Cr-Commit-Position: refs/heads/master@{#706085}
parent f97d24ac
......@@ -9,12 +9,20 @@ if (!is_ios) {
sources = [
"file_manager.cc",
"file_manager.h",
"hit_tester.cc",
"hit_tester.h",
]
deps = [
"//base",
"//cc/base",
"//ui/gfx/geometry",
"//url",
]
public_deps = [
"//components/paint_preview/common/proto",
]
}
source_set("unit_tests") {
......@@ -22,6 +30,7 @@ if (!is_ios) {
sources = [
"file_manager_unittest.cc",
"hit_tester_unittest.cc",
]
deps = [
......@@ -30,6 +39,7 @@ if (!is_ios) {
"//base/test:test_support",
"//testing/gmock",
"//testing/gtest",
"//ui/gfx/geometry",
"//url",
]
}
......
include_rules = [
"+cc/base",
]
// 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 "components/paint_preview/browser/hit_tester.h"
#include <vector>
#include "components/paint_preview/common/proto/paint_preview.pb.h"
namespace paint_preview {
namespace {
LinkData ToLinkData(const LinkDataProto& proto) {
return {gfx::Rect(proto.rect().x(), proto.rect().y(), proto.rect().width(),
proto.rect().height()),
GURL(proto.url())};
}
gfx::Rect BoundsGetter(const std::vector<LinkData>& links, size_t index) {
return links[index].rect;
}
GURL PayloadGetter(const std::vector<LinkData>& links, size_t index) {
return links[index].url;
}
} // namespace
HitTester::HitTester() = default;
HitTester::~HitTester() = default;
void HitTester::Build(const PaintPreviewFrameProto& proto) {
std::vector<LinkData> link_data;
link_data.reserve(proto.links_size());
for (const auto& link : proto.links())
link_data.push_back(ToLinkData(link));
Build(link_data);
}
void HitTester::Build(const std::vector<LinkDataProto>& links) {
std::vector<LinkData> link_data;
link_data.reserve(links.size());
for (const auto& link : links)
link_data.push_back(ToLinkData(link));
Build(link_data);
}
void HitTester::Build(const std::vector<LinkData>& links) {
rtree_.Build(links, &BoundsGetter, &PayloadGetter);
}
bool HitTester::IsValid() {
return rtree_.has_valid_bounds();
}
void HitTester::HitTest(const gfx::Rect& query,
std::vector<const GURL*>* results) const {
rtree_.SearchRefs(query, results);
}
void HitTester::Reset() {
rtree_.Reset();
}
} // namespace paint_preview
// 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.
#ifndef COMPONENTS_PAINT_PREVIEW_BROWSER_HIT_TESTER_H_
#define COMPONENTS_PAINT_PREVIEW_BROWSER_HIT_TESTER_H_
#include <vector>
#include "base/macros.h"
#include "cc/base/rtree.h"
#include "components/paint_preview/common/proto/paint_preview.pb.h"
#include "ui/gfx/geometry/rect.h"
#include "url/gurl.h"
namespace paint_preview {
// Struct for holding simple link data.
struct LinkData {
gfx::Rect rect;
GURL url;
};
// A class for hit testing to find the locations of links in a paint preview.
class HitTester {
public:
HitTester();
~HitTester();
// Builds a R-Tree from the underlying data.
void Build(const PaintPreviewFrameProto& proto);
void Build(const std::vector<LinkData>& links);
void Build(const std::vector<LinkDataProto>& links);
// Returns false if the underlying rtree is not valid.
bool IsValid();
// Finds all rects in the provided data that intersect with query and returns
// a vector of non-owning pointers to corresponding GURLs.
void HitTest(const gfx::Rect& query, std::vector<const GURL*>* results) const;
// Clears all data.
void Reset();
private:
cc::RTree<GURL> rtree_;
DISALLOW_COPY_AND_ASSIGN(HitTester);
};
} // namespace paint_preview
#endif // COMPONENTS_PAINT_PREVIEW_BROWSER_HIT_TESTER_H_
// 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 "components/paint_preview/browser/hit_tester.h"
#include <vector>
#include "components/paint_preview/common/proto/paint_preview.pb.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/geometry/rect.h"
#include "url/gurl.h"
namespace paint_preview {
// This test suite is *not* an extensive test of the underlying rtree it only
// aims to test the Build() options.
TEST(PaintPreviewHitTesterTest, TestBuildLinkData) {
HitTester hit_tester;
std::vector<LinkData> links;
GURL url("https://foo.com");
links.push_back({gfx::Rect(50, 50, 50, 50), url});
hit_tester.Build(links);
EXPECT_TRUE(hit_tester.IsValid());
std::vector<const GURL*> urls;
hit_tester.HitTest(gfx::Rect(75, 75, 1, 1), &urls);
EXPECT_EQ(urls.size(), 1U);
EXPECT_EQ(*urls[0], url);
urls.clear();
hit_tester.HitTest(gfx::Rect(1, 1, 1, 1), &urls);
EXPECT_TRUE(urls.empty());
hit_tester.Reset();
urls.clear();
hit_tester.HitTest(gfx::Rect(75, 75, 1, 1), &urls);
EXPECT_TRUE(urls.empty());
}
TEST(PaintPreviewHitTesterTest, TestBuildLinkDataProto) {
HitTester hit_tester;
std::vector<LinkDataProto> links;
LinkDataProto proto;
proto.set_url("http://bar.org");
auto* rect = proto.mutable_rect();
rect->set_x(10);
rect->set_y(20);
rect->set_width(100);
rect->set_height(50);
links.push_back(proto);
hit_tester.Build(links);
EXPECT_TRUE(hit_tester.IsValid());
std::vector<const GURL*> urls;
hit_tester.HitTest(gfx::Rect(100, 25, 1, 1), &urls);
EXPECT_EQ(urls.size(), 1U);
EXPECT_EQ(*urls[0], GURL(proto.url()));
urls.clear();
hit_tester.HitTest(gfx::Rect(25, 100, 1, 1), &urls);
EXPECT_TRUE(urls.empty());
hit_tester.Reset();
urls.clear();
hit_tester.HitTest(gfx::Rect(100, 25, 1, 1), &urls);
EXPECT_TRUE(urls.empty());
}
TEST(PaintPreviewHitTesterTest, TestBuildPaintPreviewFrameProto) {
HitTester hit_tester;
PaintPreviewFrameProto proto;
auto* link = proto.add_links();
link->set_url("http://baz.io");
auto* rect = link->mutable_rect();
rect->set_x(1);
rect->set_y(1);
rect->set_width(10);
rect->set_height(10);
hit_tester.Build(proto);
EXPECT_TRUE(hit_tester.IsValid());
std::vector<const GURL*> urls;
hit_tester.HitTest(gfx::Rect(5, 5, 1, 1), &urls);
EXPECT_EQ(urls.size(), 1U);
EXPECT_EQ(*urls[0], GURL(link->url()));
urls.clear();
hit_tester.HitTest(gfx::Rect(0, 0, 1, 1), &urls);
EXPECT_TRUE(urls.empty());
hit_tester.Reset();
urls.clear();
hit_tester.HitTest(gfx::Rect(5, 5, 1, 1), &urls);
EXPECT_TRUE(urls.empty());
}
} // namespace paint_preview
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment