diff --git a/third_party/blink/renderer/core/content_capture/content_capture_test.cc b/third_party/blink/renderer/core/content_capture/content_capture_test.cc
index 77f0ceb22e5e39..0f809054f2713a 100644
--- a/third_party/blink/renderer/core/content_capture/content_capture_test.cc
+++ b/third_party/blink/renderer/core/content_capture/content_capture_test.cc
@@ -194,7 +194,8 @@ class ContentCaptureTest : public PageTestBase,
"
6
"
"7
"
"8
"
- "");
+ ""
+ "invisible
");
platform()->SetAutoAdvanceNowToPendingTasks(false);
// TODO(michaelbai): ContentCaptureManager should be get from LocalFrame.
content_capture_manager_ =
@@ -279,6 +280,8 @@ class ContentCaptureTest : public PageTestBase,
const Vector& NodeIds() const { return node_ids_; }
const Vector> Nodes() const { return nodes_; }
+ Node& invisible_node() const { return *invisible_node_; }
+
private:
void ResetResult() {
GetWebContentCaptureClient()->ResetResults();
@@ -298,10 +301,13 @@ class ContentCaptureTest : public PageTestBase,
node_ids_.push_back(
cc::NodeInfo(DOMNodeIds::IdForNode(node), GetRect(layout_object)));
}
+ invisible_node_ = GetElementById("invisible")->firstChild();
+ DCHECK(invisible_node_.Get());
}
Vector> nodes_;
Vector node_ids_;
+ Persistent invisible_node_;
std::unique_ptr content_capture_client_;
Persistent content_capture_manager_;
Persistent local_frame_client_;
@@ -373,6 +379,30 @@ TEST_P(ContentCaptureTest, NodeOnlySendOnce) {
EXPECT_TRUE(GetWebContentCaptureClient()->RemovedData().empty());
}
+TEST_P(ContentCaptureTest, UnsentNode) {
+ // Send all nodes expect |invisible_node_|.
+ RunContentCaptureTask();
+ EXPECT_FALSE(GetWebContentCaptureClient()->Data().empty());
+ EXPECT_EQ(GetExpectedSecondResultSize(),
+ GetWebContentCaptureClient()->Data().size());
+
+ // Simulates the |invisible_node_| being changed, and verifies no content
+ // change because |invisible_node_| wasn't captured.
+ GetContentCaptureManager()->OnNodeTextChanged(invisible_node());
+ RunContentCaptureTask();
+ EXPECT_TRUE(GetWebContentCaptureClient()->Data().empty());
+ EXPECT_TRUE(GetWebContentCaptureClient()->UpdatedData().empty());
+ EXPECT_TRUE(GetWebContentCaptureClient()->RemovedData().empty());
+
+ // Simulates the |invisible_node_| being removed, and verifies no content
+ // change because |invisible_node_| wasn't captured.
+ GetContentCaptureManager()->OnLayoutTextWillBeDestroyed(invisible_node());
+ RunContentCaptureTask();
+ EXPECT_TRUE(GetWebContentCaptureClient()->Data().empty());
+ EXPECT_TRUE(GetWebContentCaptureClient()->UpdatedData().empty());
+ EXPECT_TRUE(GetWebContentCaptureClient()->RemovedData().empty());
+}
+
TEST_P(ContentCaptureTest, RemoveNodeBeforeSendingOut) {
// Capture the content, but didn't send them.
GetContentCaptureTask()->SetTaskStopState(
diff --git a/third_party/blink/renderer/core/content_capture/task_session.cc b/third_party/blink/renderer/core/content_capture/task_session.cc
index ae55385ac54813..1c63b13b7b171e 100644
--- a/third_party/blink/renderer/core/content_capture/task_session.cc
+++ b/third_party/blink/renderer/core/content_capture/task_session.cc
@@ -11,31 +11,21 @@
namespace blink {
-TaskSession::DocumentSession::DocumentSession(
- const Document& document,
- HeapHashSet>& sent_nodes,
- SentNodeCountCallback& callback)
- : document_(&document), sent_nodes_(&sent_nodes), callback_(callback) {}
+TaskSession::DocumentSession::DocumentSession(const Document& document,
+ SentNodeCountCallback& callback)
+ : document_(&document), callback_(callback) {}
TaskSession::DocumentSession::~DocumentSession() {
if (callback_.has_value())
callback_.value().Run(total_sent_nodes_);
}
-void TaskSession::DocumentSession::AddCapturedNode(Node& node,
- const gfx::Rect& rect) {
- // Replace the previous rect if any.
- captured_content_.Set(WeakMember(&node), rect);
-}
-
-void TaskSession::DocumentSession::AddDetachedNode(int64_t id) {
- detached_nodes_.emplace_back(id);
-}
-
-void TaskSession::DocumentSession::AddChangedNode(Node& node,
- const gfx::Rect& rect) {
- // Replace the previous rect if any.
- changed_content_.Set(WeakMember(&node), rect);
+bool TaskSession::DocumentSession::AddDetachedNode(const Node& node) {
+ if (sent_nodes_.Contains(&node)) {
+ detached_nodes_.emplace_back(reinterpret_cast(&node));
+ return true;
+ }
+ return false;
}
WebVector TaskSession::DocumentSession::MoveDetachedNodes() {
@@ -46,8 +36,8 @@ ContentHolder* TaskSession::DocumentSession::GetNextUnsentNode() {
while (!captured_content_.IsEmpty()) {
auto node = captured_content_.begin()->key;
const gfx::Rect rect = captured_content_.Take(node);
- if (node && node->GetLayoutObject() && !sent_nodes_->Contains(node)) {
- sent_nodes_->insert(WeakMember(node));
+ if (node && node->GetLayoutObject() && !sent_nodes_.Contains(node)) {
+ sent_nodes_.insert(WeakMember(node));
total_sent_nodes_++;
return MakeGarbageCollected(node, rect);
}
@@ -67,16 +57,40 @@ ContentHolder* TaskSession::DocumentSession::GetNextChangedNode() {
return nullptr;
}
+bool TaskSession::DocumentSession::AddChangedNode(Node& node) {
+ // No need to save the node that hasn't been sent because it will be captured
+ // once being on screen.
+ if (sent_nodes_.Contains(&node)) {
+ changed_nodes_.insert(WeakMember(&node));
+ return true;
+ }
+ return false;
+}
+
+void TaskSession::DocumentSession::OnContentCaptured(
+ Node& node,
+ const gfx::Rect& visual_rect) {
+ if (changed_nodes_.Take(&node)) {
+ changed_content_.Set(WeakMember(&node), visual_rect);
+ } else if (!sent_nodes_.Contains(&node)) {
+ captured_content_.Set(WeakMember(&node), visual_rect);
+ } // else |node| has been sent and unchanged.
+}
+
void TaskSession::DocumentSession::Trace(Visitor* visitor) const {
visitor->Trace(captured_content_);
- visitor->Trace(document_);
visitor->Trace(changed_content_);
+ visitor->Trace(document_);
+ visitor->Trace(sent_nodes_);
+ visitor->Trace(changed_nodes_);
}
void TaskSession::DocumentSession::Reset() {
changed_content_.clear();
captured_content_.clear();
detached_nodes_.Clear();
+ sent_nodes_.clear();
+ changed_nodes_.clear();
}
TaskSession::TaskSession() = default;
@@ -106,43 +120,27 @@ void TaskSession::GroupCapturedContentByDocument(
// later replace the previous.
for (const auto& i : captured_content) {
if (Node* node = DOMNodeIds::NodeForId(i.node_id)) {
- if (changed_nodes_.Take(node)) {
- // The changed node might not be sent.
- if (sent_nodes_.Contains(node)) {
- EnsureDocumentSession(node->GetDocument())
- .AddChangedNode(*node, i.visual_rect);
- } else {
- EnsureDocumentSession(node->GetDocument())
- .AddCapturedNode(*node, i.visual_rect);
- }
- continue;
- }
- if (!sent_nodes_.Contains(node)) {
- EnsureDocumentSession(node->GetDocument())
- .AddCapturedNode(*node, i.visual_rect);
- }
+ EnsureDocumentSession(node->GetDocument())
+ .OnContentCaptured(*node, i.visual_rect);
}
}
}
void TaskSession::OnNodeDetached(const Node& node) {
- if (sent_nodes_.Contains(&node)) {
- EnsureDocumentSession(node.GetDocument())
- .AddDetachedNode(reinterpret_cast(&node));
+ if (EnsureDocumentSession(node.GetDocument()).AddDetachedNode(node))
has_unsent_data_ = true;
- }
}
void TaskSession::OnNodeChanged(Node& node) {
- changed_nodes_.insert(WeakMember(&node));
+ if (EnsureDocumentSession(node.GetDocument()).AddChangedNode(node))
+ has_unsent_data_ = true;
}
TaskSession::DocumentSession& TaskSession::EnsureDocumentSession(
const Document& doc) {
DocumentSession* doc_session = GetDocumentSession(doc);
if (!doc_session) {
- doc_session =
- MakeGarbageCollected(doc, sent_nodes_, callback_);
+ doc_session = MakeGarbageCollected(doc, callback_);
to_document_session_.insert(&doc, doc_session);
}
return *doc_session;
@@ -157,8 +155,6 @@ TaskSession::DocumentSession* TaskSession::GetDocumentSession(
}
void TaskSession::Trace(Visitor* visitor) const {
- visitor->Trace(sent_nodes_);
- visitor->Trace(changed_nodes_);
visitor->Trace(to_document_session_);
}
diff --git a/third_party/blink/renderer/core/content_capture/task_session.h b/third_party/blink/renderer/core/content_capture/task_session.h
index 93b5fb71b6fe5b..38da3c4591abfc 100644
--- a/third_party/blink/renderer/core/content_capture/task_session.h
+++ b/third_party/blink/renderer/core/content_capture/task_session.h
@@ -50,12 +50,16 @@ class TaskSession final : public GarbageCollected {
using SentNodeCountCallback = base::RepeatingCallback;
DocumentSession(const Document& document,
- HeapHashSet>& sent_nodes,
SentNodeCountCallback& call_back);
~DocumentSession();
- void AddCapturedNode(Node& node, const gfx::Rect& rect);
- void AddDetachedNode(int64_t id);
- void AddChangedNode(Node& node, const gfx::Rect& rect);
+ // Add the given |node| to changed node set if the node was sent, return
+ // true if succeed.
+ bool AddChangedNode(Node& node);
+ // Add the given |node| to detached node set if the node was sent, return
+ // true if succeed.
+ bool AddDetachedNode(const Node& node);
+ // Invoked on the content of this document is captured.
+ void OnContentCaptured(Node& node, const gfx::Rect& visual_rect);
bool HasUnsentData() const {
return HasUnsentCapturedContent() || HasUnsentChangedContent() ||
HasUnsentDetachedNodes();
@@ -83,15 +87,19 @@ class TaskSession final : public GarbageCollected {
void Trace(Visitor*) const;
private:
- // The captured content that belongs to this document.
+ // The list of captured content that needs to be sent.
HeapHashMap, gfx::Rect> captured_content_;
+ // The list of changed nodes that needs to be sent.
+ HeapHashMap, gfx::Rect> changed_content_;
// The list of content id of node that has been detached from the
- // LayoutTree.
+ // LayoutTree and needs to be sent.
WebVector detached_nodes_;
+
WeakMember document_;
- HeapHashSet>* sent_nodes_;
- // The list of changed nodes that needs to be sent.
- HeapHashMap, gfx::Rect> changed_content_;
+ // A set of weak reference of the node that has been sent.
+ HeapHashSet> sent_nodes_;
+ // A set of node whose value has been changed since last capture.
+ HeapHashSet> changed_nodes_;
bool first_data_has_sent_ = false;
// This is for the metrics to record the total node that has been sent.
@@ -131,12 +139,6 @@ class TaskSession final : public GarbageCollected {
DocumentSession& EnsureDocumentSession(const Document& doc);
DocumentSession* GetDocumentSession(const Document& document) const;
- // A set of weak reference of the node that has been sent.
- HeapHashSet> sent_nodes_;
-
- // The list of node whose value has changed.
- HeapHashSet> changed_nodes_;
-
// This owns the DocumentSession which is released along with Document.
HeapHashMap, Member>
to_document_session_;