[performance_manager] Add an operation for visiting a page and its embeds
Introduce GraphOperations::VisitPageAndEmbedsPreOrder to run a visitor
for a PageNode and all PageNodes embedded within it. This is useful for
scenarios such as guest views, where one WebContents embeds another.
Bug: 40925658
AX-Relnotes: n/a.
Change-Id: I212a1e98de890e5d3675b2eeee698034dfa2ec0e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5352066
Reviewed-by: Joe Mason <joenotcharles@google.com>
Commit-Queue: Greg Thompson <grt@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1341520}
diff --git a/components/performance_manager/graph/graph_impl_operations.cc b/components/performance_manager/graph/graph_impl_operations.cc
index 2883d1f..9957ab04 100644
--- a/components/performance_manager/graph/graph_impl_operations.cc
+++ b/components/performance_manager/graph/graph_impl_operations.cc
@@ -167,6 +167,31 @@
}
// static
+bool GraphImplOperations::VisitPageAndEmbedsPreOrder(
+ PageNodeImpl* page,
+ PageNodeImplVisitor visitor) {
+ if (!visitor(page)) {
+ return false;
+ }
+
+ for (FrameNodeImpl* main_frame_node : page->main_frame_nodes()) {
+ if (!VisitFrameAndChildrenPreOrder(
+ main_frame_node, [&visitor](FrameNodeImpl* frame_node) {
+ const FrameNode* const node = frame_node;
+ for (const auto* page_node : node->GetEmbeddedPageNodes()) {
+ if (!visitor(PageNodeImpl::FromNode(page_node))) {
+ return false;
+ }
+ }
+ return true;
+ })) {
+ return false;
+ }
+ }
+ return true;
+}
+
+// static
bool GraphImplOperations::HasFrame(const PageNodeImpl* page,
FrameNodeImpl* frame) {
bool has_frame = false;
diff --git a/components/performance_manager/graph/graph_impl_operations.h b/components/performance_manager/graph/graph_impl_operations.h
index ff67c60..344e342 100644
--- a/components/performance_manager/graph/graph_impl_operations.h
+++ b/components/performance_manager/graph/graph_impl_operations.h
@@ -20,6 +20,7 @@
// graph.
struct GraphImplOperations {
using FrameNodeImplVisitor = base::FunctionRef<bool(FrameNodeImpl*)>;
+ using PageNodeImplVisitor = base::FunctionRef<bool(PageNodeImpl*)>;
using WorkerNodeImplVisitor = base::FunctionRef<bool(WorkerNodeImpl*)>;
// Returns the collection of page nodes that are associated with the given
@@ -59,6 +60,12 @@
static bool VisitFrameTreePostOrder(const PageNodeImpl* page,
FrameNodeImplVisitor visitor);
+ // Traverses the tree of embedded pages rooted at `page`, invoking `visitor`
+ // for each page node. Returns false if `visitor` returns false (stopping the
+ // traversal at that point); otherwise, returns `true`.
+ static bool VisitPageAndEmbedsPreOrder(PageNodeImpl* page,
+ PageNodeImplVisitor visitor);
+
// Returns true if the given |frame| is in the frame tree associated with the
// given |page|.
static bool HasFrame(const PageNodeImpl* page, FrameNodeImpl* frame);
diff --git a/components/performance_manager/graph/graph_operations.cc b/components/performance_manager/graph/graph_operations.cc
index 342ba76..adfdc511 100644
--- a/components/performance_manager/graph/graph_operations.cc
+++ b/components/performance_manager/graph/graph_operations.cc
@@ -58,6 +58,14 @@
}
// static
+bool GraphOperations::VisitPageAndEmbedsPreOrder(const PageNode* page,
+ PageNodeVisitor visitor) {
+ return GraphImplOperations::VisitPageAndEmbedsPreOrder(
+ PageNodeImpl::FromNode(page),
+ [&visitor](PageNodeImpl* page_impl) { return visitor(page_impl); });
+}
+
+// static
bool GraphOperations::HasFrame(const PageNode* page, const FrameNode* frame) {
return GraphImplOperations::HasFrame(PageNodeImpl::FromNode(page),
FrameNodeImpl::FromNode(frame));
diff --git a/components/performance_manager/graph/graph_operations_unittest.cc b/components/performance_manager/graph/graph_operations_unittest.cc
index 9fde47a3..0690b59 100644
--- a/components/performance_manager/graph/graph_operations_unittest.cc
+++ b/components/performance_manager/graph/graph_operations_unittest.cc
@@ -26,6 +26,7 @@
process2_ = CreateNode<ProcessNodeImpl>();
page1_ = CreateNode<PageNodeImpl>();
page2_ = CreateNode<PageNodeImpl>();
+ page3_ = CreateNode<PageNodeImpl>();
mainframe1_ = CreateFrameNodeAutoId(process1_.get(), page1_.get(), nullptr);
mainframe2_ = CreateFrameNodeAutoId(process2_.get(), page2_.get(), nullptr);
childframe1a_ =
@@ -36,12 +37,15 @@
CreateFrameNodeAutoId(process1_.get(), page2_.get(), mainframe2_.get());
childframe2b_ =
CreateFrameNodeAutoId(process1_.get(), page2_.get(), mainframe2_.get());
+ page3_->SetEmbedderFrameNodeAndEmbeddingType(
+ mainframe1_.get(), PageNode::EmbeddingType::kGuestView);
}
TestNodeWrapper<ProcessNodeImpl> process1_;
TestNodeWrapper<ProcessNodeImpl> process2_;
TestNodeWrapper<PageNodeImpl> page1_;
TestNodeWrapper<PageNodeImpl> page2_;
+ TestNodeWrapper<PageNodeImpl> page3_; // A guest of `page1_`.
// Root nodes. |mainframeX_| is in |processX_|.
TestNodeWrapper<FrameNodeImpl> mainframe1_;
@@ -144,6 +148,27 @@
EXPECT_EQ(1u, visited.size());
}
+TEST_F(GraphOperationsTest, VisitPageEmbeds) {
+ // Pages are visited embedder-to-embedded.
+ std::vector<const PageNode*> visited;
+ ASSERT_TRUE(GraphOperations::VisitPageAndEmbedsPreOrder(
+ page1_.get(), [&visited](const PageNode* page_node) {
+ visited.push_back(page_node);
+ return true;
+ }));
+ EXPECT_THAT(visited, testing::ElementsAre(ToPublic(page1_.get()),
+ ToPublic(page3_.get())));
+
+ // Stop after the first item.
+ visited.clear();
+ ASSERT_FALSE(GraphOperations::VisitPageAndEmbedsPreOrder(
+ page1_.get(), [&visited](const PageNode* page_node) {
+ visited.push_back(page_node);
+ return false;
+ }));
+ EXPECT_THAT(visited, testing::ElementsAre(ToPublic(page1_.get())));
+}
+
TEST_F(GraphOperationsTest, HasFrame) {
EXPECT_TRUE(GraphOperations::HasFrame(page1_.get(), childframe1a_.get()));
EXPECT_FALSE(GraphOperations::HasFrame(page1_.get(), childframe2a_.get()));
diff --git a/components/performance_manager/public/graph/graph_operations.h b/components/performance_manager/public/graph/graph_operations.h
index df00f00..1dc019f 100644
--- a/components/performance_manager/public/graph/graph_operations.h
+++ b/components/performance_manager/public/graph/graph_operations.h
@@ -19,6 +19,7 @@
// graph.
struct GraphOperations {
using FrameNodeVisitor = base::FunctionRef<bool(const FrameNode*)>;
+ using PageNodeVisitor = base::FunctionRef<bool(const PageNode*)>;
using WorkerNodeVisitor = base::FunctionRef<bool(const WorkerNode*)>;
// Returns the collection of page nodes that are associated with the given
@@ -47,6 +48,12 @@
static bool VisitFrameTreePostOrder(const PageNode* page,
FrameNodeVisitor visitor);
+ // Traverses the tree of embedded pages rooted at `page`, invoking `visitor`
+ // for each page node. Returns false if `visitor` returns false (stopping the
+ // traversal at that point); otherwise, returns `true`.
+ static bool VisitPageAndEmbedsPreOrder(const PageNode* page,
+ PageNodeVisitor visitor);
+
// Returns true if the given |frame| is in the frame tree associated with the
// given |page|.
static bool HasFrame(const PageNode* page, const FrameNode* frame);