Commit 52d8ec7a authored by Tao Bai's avatar Tao Bai Committed by Commit Bot

ContentCapture: Support content change

The some changes of element will not cause remove/add LayoutText,
instead, LayoutText is changed.

This patch supports the content change in this case, DidUpdateContent()
is added and invoked after new content is sent.

Bug: 952973
Change-Id: Ia530e7e71570801f1f494bd584526cc7dc3ccba8
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1598310
Commit-Queue: Tao Bai <michaelbai@chromium.org>
Reviewed-by: default avatarTobias Sargeant <tobiasjs@chromium.org>
Reviewed-by: default avatarXianzhu Wang <wangxianzhu@chromium.org>
Reviewed-by: default avatarPhilip Rogers <pdr@chromium.org>
Cr-Commit-Position: refs/heads/master@{#659145}
parent 2611e35d
...@@ -69,6 +69,9 @@ void ContentCaptureSender::DidCaptureContent( ...@@ -69,6 +69,9 @@ void ContentCaptureSender::DidCaptureContent(
GetContentCaptureReceiver()->DidCaptureContent(frame_data, first_data); GetContentCaptureReceiver()->DidCaptureContent(frame_data, first_data);
} }
void ContentCaptureSender::DidUpdateContent(
const std::vector<scoped_refptr<blink::WebContentHolder>>& data) {}
void ContentCaptureSender::DidRemoveContent(const std::vector<int64_t>& data) { void ContentCaptureSender::DidRemoveContent(const std::vector<int64_t>& data) {
GetContentCaptureReceiver()->DidRemoveContent(data); GetContentCaptureReceiver()->DidRemoveContent(data);
} }
......
...@@ -42,9 +42,11 @@ class ContentCaptureSender : public content::RenderFrameObserver, ...@@ -42,9 +42,11 @@ class ContentCaptureSender : public content::RenderFrameObserver,
void DidCaptureContent( void DidCaptureContent(
const std::vector<scoped_refptr<blink::WebContentHolder>>& data, const std::vector<scoped_refptr<blink::WebContentHolder>>& data,
bool first_data) override; bool first_data) override;
void DidUpdateContent(
const std::vector<scoped_refptr<blink::WebContentHolder>>& data) override;
void DidRemoveContent(const std::vector<int64_t>& data) override; void DidRemoveContent(const std::vector<int64_t>& data) override;
// mojom::ContentCaptureSender // mojom::ContentCaptureSender:
void StartCapture() override; void StartCapture() override;
void StopCapture() override; void StopCapture() override;
......
...@@ -31,6 +31,10 @@ class WebContentCaptureClient { ...@@ -31,6 +31,10 @@ class WebContentCaptureClient {
const std::vector<scoped_refptr<WebContentHolder>>& content, const std::vector<scoped_refptr<WebContentHolder>>& content,
bool first_data) = 0; bool first_data) = 0;
// Invoked when a list of |content| is updated.
virtual void DidUpdateContent(
const std::vector<scoped_refptr<WebContentHolder>>& content) = 0;
// Invoked when the previously captured content is removed, |content_ids| is a // Invoked when the previously captured content is removed, |content_ids| is a
// list of removed content id. // list of removed content id.
virtual void DidRemoveContent(const std::vector<int64_t>& content_ids) = 0; virtual void DidRemoveContent(const std::vector<int64_t>& content_ids) = 0;
......
...@@ -69,6 +69,11 @@ void ContentCaptureManager::OnScrollPositionChanged() { ...@@ -69,6 +69,11 @@ void ContentCaptureManager::OnScrollPositionChanged() {
ScheduleTask(ContentCaptureTask::ScheduleReason::kScrolling); ScheduleTask(ContentCaptureTask::ScheduleReason::kScrolling);
} }
void ContentCaptureManager::OnNodeTextChanged(const NodeHolder& node_holder) {
task_session_->OnNodeChanged(node_holder);
ScheduleTask(ContentCaptureTask::ScheduleReason::kContentChange);
}
void ContentCaptureManager::Trace(Visitor* visitor) { void ContentCaptureManager::Trace(Visitor* visitor) {
visitor->Trace(local_frame_root_); visitor->Trace(local_frame_root_);
visitor->Trace(task_session_); visitor->Trace(task_session_);
......
...@@ -36,6 +36,9 @@ class CORE_EXPORT ContentCaptureManager ...@@ -36,6 +36,9 @@ class CORE_EXPORT ContentCaptureManager
// Invokes when scroll position was changed. // Invokes when scroll position was changed.
void OnScrollPositionChanged(); void OnScrollPositionChanged();
// Invokes when text node content was changed.
void OnNodeTextChanged(const NodeHolder& node_holder);
// Invokes when the local_frame_root shutdown. // Invokes when the local_frame_root shutdown.
void Shutdown(); void Shutdown();
......
...@@ -77,23 +77,33 @@ void ContentCaptureTask::SendContent( ...@@ -77,23 +77,33 @@ void ContentCaptureTask::SendContent(
TaskSession::DocumentSession& doc_session) { TaskSession::DocumentSession& doc_session) {
auto* document = doc_session.GetDocument(); auto* document = doc_session.GetDocument();
DCHECK(document); DCHECK(document);
auto* client = GetWebContentCaptureClient(*document);
DCHECK(client);
if (histogram_reporter_) if (histogram_reporter_)
histogram_reporter_->OnSendContentStarted(); histogram_reporter_->OnSendContentStarted();
std::vector<scoped_refptr<WebContentHolder>> content_batch; std::vector<scoped_refptr<WebContentHolder>> content_batch;
content_batch.reserve(kBatchSize); content_batch.reserve(kBatchSize);
// Only send changed content after the new content was sent.
bool sending_changed_content = !doc_session.HasUnsentCapturedContent();
while (content_batch.size() < kBatchSize) { while (content_batch.size() < kBatchSize) {
scoped_refptr<ContentHolder> content_holder = scoped_refptr<ContentHolder> content_holder;
doc_session.GetNextUnsentContentHolder(); if (sending_changed_content)
content_holder = doc_session.GetNextChangedContentHolder();
else
content_holder = doc_session.GetNextUnsentContentHolder();
if (!content_holder) if (!content_holder)
break; break;
content_batch.push_back( content_batch.push_back(
base::MakeRefCounted<WebContentHolder>(content_holder)); base::MakeRefCounted<WebContentHolder>(content_holder));
} }
if (!content_batch.empty()) { if (!content_batch.empty()) {
DCHECK(GetWebContentCaptureClient(*document)); if (sending_changed_content) {
GetWebContentCaptureClient(*document)->DidCaptureContent( client->DidUpdateContent(content_batch);
content_batch, !doc_session.FirstDataHasSent()); } else {
doc_session.SetFirstDataHasSent(); client->DidCaptureContent(content_batch, !doc_session.FirstDataHasSent());
doc_session.SetFirstDataHasSent();
}
} }
if (histogram_reporter_) if (histogram_reporter_)
histogram_reporter_->OnSendContentEnded(content_batch.size()); histogram_reporter_->OnSendContentEnded(content_batch.size());
...@@ -128,7 +138,8 @@ bool ContentCaptureTask::ProcessDocumentSession( ...@@ -128,7 +138,8 @@ bool ContentCaptureTask::ProcessDocumentSession(
return true; return true;
} }
while (doc_session.HasUnsentCapturedContent()) { while (doc_session.HasUnsentCapturedContent() ||
doc_session.HasUnsentChangedContent()) {
SendContent(doc_session); SendContent(doc_session);
if (ShouldPause()) { if (ShouldPause()) {
return !doc_session.HasUnsentData(); return !doc_session.HasUnsentData();
......
...@@ -31,6 +31,11 @@ void TaskSession::DocumentSession::AddDetachedNode(int64_t id) { ...@@ -31,6 +31,11 @@ void TaskSession::DocumentSession::AddDetachedNode(int64_t id) {
detached_nodes_.push_back(id); detached_nodes_.push_back(id);
} }
void TaskSession::DocumentSession::AddChangedNodeHolder(
cc::NodeHolder node_holder) {
changed_content_.push_back(node_holder);
}
std::vector<int64_t> TaskSession::DocumentSession::MoveDetachedNodes() { std::vector<int64_t> TaskSession::DocumentSession::MoveDetachedNodes() {
return std::move(detached_nodes_); return std::move(detached_nodes_);
} }
...@@ -64,12 +69,36 @@ TaskSession::DocumentSession::GetNextUnsentContentHolder() { ...@@ -64,12 +69,36 @@ TaskSession::DocumentSession::GetNextUnsentContentHolder() {
return content_holder; return content_holder;
} }
scoped_refptr<blink::ContentHolder>
TaskSession::DocumentSession::GetNextChangedContentHolder() {
scoped_refptr<ContentHolder> content_holder;
while (!changed_content_.empty() && !content_holder) {
auto node_holder = changed_content_.back();
if (node_holder.type == cc::NodeHolder::Type::kID) {
Node* node = DOMNodeIds::NodeForId(node_holder.id);
if (node && node->GetLayoutObject())
content_holder = base::MakeRefCounted<ContentHolder>(*node);
} else if (node_holder.type == cc::NodeHolder::Type::kTextHolder &&
node_holder.text_holder) {
content_holder = scoped_refptr<ContentHolder>(
static_cast<ContentHolder*>(node_holder.text_holder.get()));
if (content_holder && !content_holder->IsValid())
content_holder.reset();
}
changed_content_.pop_back();
}
if (content_holder)
total_sent_nodes_++;
return content_holder;
}
void TaskSession::DocumentSession::Trace(blink::Visitor* visitor) { void TaskSession::DocumentSession::Trace(blink::Visitor* visitor) {
visitor->Trace(sent_nodes_); visitor->Trace(sent_nodes_);
visitor->Trace(document_); visitor->Trace(document_);
} }
void TaskSession::DocumentSession::Reset() { void TaskSession::DocumentSession::Reset() {
changed_content_.clear();
captured_content_.clear(); captured_content_.clear();
detached_nodes_.clear(); detached_nodes_.clear();
} }
...@@ -97,6 +126,19 @@ void TaskSession::SetCapturedContent( ...@@ -97,6 +126,19 @@ void TaskSession::SetCapturedContent(
void TaskSession::GroupCapturedContentByDocument( void TaskSession::GroupCapturedContentByDocument(
const std::vector<cc::NodeHolder>& captured_content) { const std::vector<cc::NodeHolder>& captured_content) {
for (const cc::NodeHolder& node_holder : captured_content) { for (const cc::NodeHolder& node_holder : captured_content) {
if (const Node* node = GetNode(node_holder)) {
node = changed_nodes_.Take(node);
if (node) {
// The changed node might not be sent.
if (GetNodeIf(true, node_holder)) {
EnsureDocumentSession(node->GetDocument())
.AddChangedNodeHolder(node_holder);
} else {
EnsureDocumentSession(node->GetDocument()).AddNodeHolder(node_holder);
}
continue;
}
}
if (const Node* node = GetNodeIf(false /* sent */, node_holder)) { if (const Node* node = GetNodeIf(false /* sent */, node_holder)) {
EnsureDocumentSession(node->GetDocument()).AddNodeHolder(node_holder); EnsureDocumentSession(node->GetDocument()).AddNodeHolder(node_holder);
} }
...@@ -111,6 +153,12 @@ void TaskSession::OnNodeDetached(const cc::NodeHolder& node_holder) { ...@@ -111,6 +153,12 @@ void TaskSession::OnNodeDetached(const cc::NodeHolder& node_holder) {
} }
} }
void TaskSession::OnNodeChanged(const cc::NodeHolder& node_holder) {
if (const Node* node = GetNode(node_holder)) {
changed_nodes_.insert(WeakMember<const Node>(node));
}
}
const Node* TaskSession::GetNodeIf(bool sent, const Node* TaskSession::GetNodeIf(bool sent,
const cc::NodeHolder& node_holder) const { const cc::NodeHolder& node_holder) const {
Node* node = nullptr; Node* node = nullptr;
...@@ -129,6 +177,19 @@ const Node* TaskSession::GetNodeIf(bool sent, ...@@ -129,6 +177,19 @@ const Node* TaskSession::GetNodeIf(bool sent,
return nullptr; return nullptr;
} }
const Node* TaskSession::GetNode(const cc::NodeHolder& node_holder) const {
if (node_holder.type == cc::NodeHolder::Type::kID)
return DOMNodeIds::NodeForId(node_holder.id);
if (node_holder.type == cc::NodeHolder::Type::kTextHolder) {
ContentHolder* content_holder =
static_cast<ContentHolder*>(node_holder.text_holder.get());
if (content_holder)
return content_holder->GetNode();
}
return nullptr;
}
TaskSession::DocumentSession& TaskSession::EnsureDocumentSession( TaskSession::DocumentSession& TaskSession::EnsureDocumentSession(
const Document& doc) { const Document& doc) {
DocumentSession* doc_session = GetDocumentSession(doc); DocumentSession* doc_session = GetDocumentSession(doc);
...@@ -150,6 +211,7 @@ TaskSession::DocumentSession* TaskSession::GetDocumentSession( ...@@ -150,6 +211,7 @@ TaskSession::DocumentSession* TaskSession::GetDocumentSession(
void TaskSession::Trace(blink::Visitor* visitor) { void TaskSession::Trace(blink::Visitor* visitor) {
visitor->Trace(sent_nodes_); visitor->Trace(sent_nodes_);
visitor->Trace(changed_nodes_);
visitor->Trace(to_document_session_); visitor->Trace(to_document_session_);
} }
......
...@@ -54,10 +54,13 @@ class TaskSession : public GarbageCollectedFinalized<TaskSession> { ...@@ -54,10 +54,13 @@ class TaskSession : public GarbageCollectedFinalized<TaskSession> {
~DocumentSession(); ~DocumentSession();
void AddNodeHolder(cc::NodeHolder node_holder); void AddNodeHolder(cc::NodeHolder node_holder);
void AddDetachedNode(int64_t id); void AddDetachedNode(int64_t id);
void AddChangedNodeHolder(cc::NodeHolder node);
bool HasUnsentData() const { bool HasUnsentData() const {
return HasUnsentCapturedContent() || HasUnsentDetachedNodes(); return HasUnsentCapturedContent() || HasUnsentChangedContent() ||
HasUnsentDetachedNodes();
} }
bool HasUnsentCapturedContent() const { return !captured_content_.empty(); } bool HasUnsentCapturedContent() const { return !captured_content_.empty(); }
bool HasUnsentChangedContent() const { return !changed_content_.empty(); }
bool HasUnsentDetachedNodes() const { return !detached_nodes_.empty(); } bool HasUnsentDetachedNodes() const { return !detached_nodes_.empty(); }
std::vector<int64_t> MoveDetachedNodes(); std::vector<int64_t> MoveDetachedNodes();
const Document* GetDocument() const { return document_; } const Document* GetDocument() const { return document_; }
...@@ -68,6 +71,8 @@ class TaskSession : public GarbageCollectedFinalized<TaskSession> { ...@@ -68,6 +71,8 @@ class TaskSession : public GarbageCollectedFinalized<TaskSession> {
// ContentHolder. // ContentHolder.
scoped_refptr<ContentHolder> GetNextUnsentContentHolder(); scoped_refptr<ContentHolder> GetNextUnsentContentHolder();
scoped_refptr<ContentHolder> GetNextChangedContentHolder();
// Resets the |captured_content_| and the |detached_nodes_|, shall only be // Resets the |captured_content_| and the |detached_nodes_|, shall only be
// used if those data doesn't need to be sent, e.g. there is no // used if those data doesn't need to be sent, e.g. there is no
// WebContentCaptureClient for this document. // WebContentCaptureClient for this document.
...@@ -83,6 +88,9 @@ class TaskSession : public GarbageCollectedFinalized<TaskSession> { ...@@ -83,6 +88,9 @@ class TaskSession : public GarbageCollectedFinalized<TaskSession> {
std::vector<int64_t> detached_nodes_; std::vector<int64_t> detached_nodes_;
WeakMember<const Document> document_; WeakMember<const Document> document_;
Member<SentNodes> sent_nodes_; Member<SentNodes> sent_nodes_;
// The list of changed nodes that needs to be sent.
std::vector<cc::NodeHolder> changed_content_;
bool first_data_has_sent_ = false; bool first_data_has_sent_ = false;
// This is for the metrics to record the total node that has been sent. // This is for the metrics to record the total node that has been sent.
size_t total_sent_nodes_ = 0; size_t total_sent_nodes_ = 0;
...@@ -102,6 +110,8 @@ class TaskSession : public GarbageCollectedFinalized<TaskSession> { ...@@ -102,6 +110,8 @@ class TaskSession : public GarbageCollectedFinalized<TaskSession> {
void OnNodeDetached(const cc::NodeHolder& node_holder); void OnNodeDetached(const cc::NodeHolder& node_holder);
void OnNodeChanged(const cc::NodeHolder& node_holder);
bool HasUnsentData() const { return has_unsent_data_; } bool HasUnsentData() const { return has_unsent_data_; }
void SetSentNodeCountCallback( void SetSentNodeCountCallback(
...@@ -119,9 +129,13 @@ class TaskSession : public GarbageCollectedFinalized<TaskSession> { ...@@ -119,9 +129,13 @@ class TaskSession : public GarbageCollectedFinalized<TaskSession> {
DocumentSession& EnsureDocumentSession(const Document& doc); DocumentSession& EnsureDocumentSession(const Document& doc);
DocumentSession* GetDocumentSession(const Document& document) const; DocumentSession* GetDocumentSession(const Document& document) const;
const Node* GetNodeIf(bool sent, const cc::NodeHolder& node_holder) const; const Node* GetNodeIf(bool sent, const cc::NodeHolder& node_holder) const;
const Node* GetNode(const cc::NodeHolder& node_holder) const;
Member<SentNodes> sent_nodes_; Member<SentNodes> sent_nodes_;
// The list of node whose value has changed.
HeapHashSet<WeakMember<const Node>> changed_nodes_;
// This owns the DocumentSession which is released along with Document. // This owns the DocumentSession which is released along with Document.
HeapHashMap<WeakMember<const Document>, Member<DocumentSession>> HeapHashMap<WeakMember<const Document>, Member<DocumentSession>>
to_document_session_; to_document_session_;
......
...@@ -1873,6 +1873,11 @@ void LayoutText::SetText(scoped_refptr<StringImpl> text, ...@@ -1873,6 +1873,11 @@ void LayoutText::SetText(scoped_refptr<StringImpl> text,
if (text_autosizer) if (text_autosizer)
text_autosizer->Record(this); text_autosizer->Record(this);
if (HasNodeHolder()) {
if (auto* content_capture_manager = GetContentCaptureManager())
content_capture_manager->OnNodeTextChanged(node_holder_);
}
valid_ng_items_ = false; valid_ng_items_ = false;
SetNeedsCollectInlines(); SetNeedsCollectInlines();
} }
......
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