Index: content/browser/find_request_manager.cc |
diff --git a/content/browser/find_request_manager.cc b/content/browser/find_request_manager.cc |
index 915ecf8d9fd51fead4daa96df981924bbf1d753a..43103b54dae23fb4058fe6badaed14fcadbd7587 100644 |
--- a/content/browser/find_request_manager.cc |
+++ b/content/browser/find_request_manager.cc |
@@ -11,13 +11,85 @@ |
namespace content { |
+namespace { |
+ |
+// Returns the key for the frame associated with |rfh|. |
+FindRequestManager::FrameKey GetFrameKey(RenderFrameHost* rfh) { |
+ return std::make_pair(rfh->GetProcess()->GetID(), rfh->GetRoutingID()); |
+} |
+ |
+// Returns the RenderFrameHostImpl associated with |frame_key|. |
+RenderFrameHostImpl* GetRenderFrameHost( |
+ const FindRequestManager::FrameKey& frame_key) { |
+ return RenderFrameHostImpl::FromID(frame_key.first, frame_key.second); |
+} |
+ |
+// Returns the deepest last child frame under |node|/|rfh| in the frame tree. |
+FrameTreeNode* GetDeepestLastChild(FrameTreeNode* node) { |
+ while (node->child_count()) |
+ node = node->child_at(node->child_count() - 1); |
+ return node; |
+} |
+RenderFrameHost* GetDeepestLastChild(RenderFrameHost* rfh) { |
lfg
2016/05/13 20:15:40
nit: newline
paulmeyer
2016/05/16 15:25:11
I actually put them together on purpose since they
lfg
2016/05/16 16:03:29
Acknowledged.
|
+ FrameTreeNode* node = |
+ static_cast<RenderFrameHostImpl*>(rfh)->frame_tree_node(); |
+ return GetDeepestLastChild(node)->current_frame_host(); |
+} |
+ |
+// Returns the FrameTreeNode directly after |node| in the frame tree in search |
+// order, or nullptr if one does not exist. If |wrap| is set, then wrapping |
+// between the first and last frames is permitted. Note that this traversal |
+// follows the same ordering as in blink::FrameTree::traverseNextWithWrap(). |
+FrameTreeNode* TraverseNext(FrameTreeNode* node, bool wrap) { |
+ if (node->child_count()) |
+ return node->child_at(0); |
+ |
+ FrameTreeNode* sibling = node->NextSibling(); |
+ while (!sibling) { |
+ if (!node->parent()) |
+ return wrap ? node : nullptr; |
+ node = node->parent(); |
+ sibling = node->NextSibling(); |
+ } |
+ return sibling; |
+} |
+ |
+// Returns the FrameTreeNode directly before |node| in the frame tree in search |
+// order, or nullptr if one does not exist. If |wrap| is set, then wrapping |
+// between the first and last frames is permitted. Note that this traversal |
+// follows the same ordering as in blink::FrameTree::traversePreviousWithWrap(). |
+FrameTreeNode* TraversePrevious(FrameTreeNode* node, bool wrap) { |
+ if (FrameTreeNode* previous_sibling = node->PreviousSibling()) |
+ return GetDeepestLastChild(previous_sibling); |
+ if (node->parent()) |
+ return node->parent(); |
+ return wrap ? GetDeepestLastChild(node) : nullptr; |
+} |
+ |
+// The same as either TraverseNext() or TraversePrevious() depending on |
+// |forward|. |
+FrameTreeNode* TraverseNode(FrameTreeNode* node, bool forward, bool wrap) { |
+ return forward ? TraverseNext(node, wrap) : TraversePrevious(node, wrap); |
+} |
+ |
+} // namespace |
+ |
+#if defined(OS_ANDROID) |
+FindRequestManager::FindMatchRectsState::FindMatchRectsState() = default; |
+FindRequestManager::FindMatchRectsState::~FindMatchRectsState() {} |
+#endif |
+ |
// static |
const int FindRequestManager::kInvalidId = -1; |
FindRequestManager::FindRequestManager(WebContentsImpl* web_contents) |
- : contents_(web_contents), |
+ : WebContentsObserver(web_contents), |
+ contents_(web_contents), |
current_session_id_(kInvalidId), |
+ pending_active_match_ordinal_(kInvalidId), |
number_of_matches_(0), |
+ relative_active_match_ordinal_( |
+ std::make_pair(std::make_pair(kInvalidId, kInvalidId), 0)), |
active_match_ordinal_(0) {} |
FindRequestManager::~FindRequestManager() {} |
@@ -31,28 +103,25 @@ void FindRequestManager::Find(int request_id, |
DCHECK_GT(request_id, current_request_.id); |
DCHECK_GT(request_id, current_session_id_); |
- FindRequest request(request_id, search_text, options); |
- |
- if (options.findNext) { |
- // This is a find next operation. |
- |
- // This implies that there is an ongoing find session with the same search |
- // text. |
- DCHECK_GE(current_session_id_, 0); |
- DCHECK_EQ(request.search_text, current_request_.search_text); |
- |
- current_request_ = request; |
- } else { |
- // This is an initial find operation. |
- Reset(request); |
+ // If this is a new find session, clear any queued requests from last session. |
+ if (!options.findNext) { |
+ find_request_queue_ = std::queue<FindRequest>(); |
} |
- SendFindIPC(request, contents_->GetMainFrame()); |
+ find_request_queue_.emplace(request_id, search_text, options); |
+ if (find_request_queue_.size() == 1) |
+ FindInternal(find_request_queue_.front()); |
} |
void FindRequestManager::StopFinding(StopFindAction action) { |
- SendStopFindingIPC(action, contents_->GetMainFrame()); |
+ contents_->ForEachFrame(base::Bind( |
+ &FindRequestManager::SendStopFindingIPC, base::Unretained(this), action)); |
current_session_id_ = kInvalidId; |
+#if defined(OS_ANDROID) |
+ // It is important that these pending replies are cleared whenever a find |
+ // session ends, so that subsequent replies for the old session are ignored. |
+ match_rects_.pending_replies.clear(); |
+#endif |
} |
void FindRequestManager::OnFindReply(RenderFrameHost* rfh, |
@@ -64,29 +133,155 @@ void FindRequestManager::OnFindReply(RenderFrameHost* rfh, |
// Ignore stale replies from abandoned find sessions. |
if (current_session_id_ == kInvalidId || request_id < current_session_id_) |
return; |
+ DCHECK(CheckFrame(rfh)); |
lfg
2016/05/13 20:15:40
Should we also check the rfh is in pending_replies
paulmeyer
2016/05/16 15:25:11
In this case no, since it is sometimes possible fo
|
+ |
+ FrameKey frame_key = GetFrameKey(rfh); |
// Update the stored results. |
- number_of_matches_ = number_of_matches; |
- selection_rect_ = selection_rect; |
- active_match_ordinal_ = active_match_ordinal; |
+ if (number_of_matches != -1) { |
+ DCHECK_GE(number_of_matches, 0); |
+ // Increment the global number of matches by the number of additional |
+ // matches found for this frame. |
+ auto matches_per_frame_it = matches_per_frame_.find(frame_key); |
+ number_of_matches_ += number_of_matches - matches_per_frame_it->second; |
+ matches_per_frame_it->second = number_of_matches; |
+ } |
+ if (!selection_rect.IsEmpty()) { |
lfg
2016/05/13 20:15:40
nit: no need for {}
paulmeyer
2016/05/16 15:25:11
Done.
|
+ selection_rect_ = selection_rect; |
+ } |
+ if (active_match_ordinal > 0) { |
+ if (GetFrameKey(rfh) == relative_active_match_ordinal_.first) { |
+ active_match_ordinal_ += |
+ active_match_ordinal - relative_active_match_ordinal_.second; |
+ relative_active_match_ordinal_.second = active_match_ordinal; |
+ } else { |
+ if (relative_active_match_ordinal_.first.first != kInvalidId) { |
+ RenderFrameHost* old_rfh = |
+ GetRenderFrameHost(relative_active_match_ordinal_.first); |
+ if (old_rfh && old_rfh != rfh) { |
+ old_rfh->Send(new FrameMsg_ClearActiveFindMatch( |
+ old_rfh->GetRoutingID())); |
+ } |
+ } |
+ relative_active_match_ordinal_ = |
+ std::make_pair(GetFrameKey(rfh), active_match_ordinal); |
+ UpdateActiveMatchOrdinal(); |
+ } |
+ if (pending_active_match_ordinal_ == request_id) |
+ pending_active_match_ordinal_ = kInvalidId; |
+ AdvanceQueue(request_id); |
+ } |
- NotifyFindReply(request_id, final_update); |
+ if (!final_update) { |
+ NotifyFindReply(request_id, false /* final_update */); |
+ return; |
+ } |
+ |
+ // This is the final update for this frame for the current find operation. |
+ |
+ pending_replies_.erase(frame_key); |
+ if (request_id == current_session_id_ && !pending_replies_.empty()) { |
+ NotifyFindReply(request_id, false /* final_update */); |
+ return; |
+ } |
+ DCHECK(request_id == current_session_id_ || |
+ current_request_.options.findNext); |
+ |
+ // This is the final update for the current find operation. |
+ FinalUpdate(request_id, rfh); |
+} |
+ |
+void FindRequestManager::RemoveFrame(RenderFrameHost* rfh) { |
+ RemoveFrame(GetFrameKey(rfh)); |
+} |
+ |
+void FindRequestManager::RemoveFrame(const FrameKey& frame_key) { |
+ if (current_session_id_ == kInvalidId || !CheckFrame(frame_key)) |
+ return; |
+ |
+ if (pending_replies_.count(frame_key)) { |
+ // A reply should not be expected from the removed frame. |
+ pending_replies_.erase(frame_key); |
+ if (pending_replies_.empty()) { |
+ FinalUpdate(current_session_id_, GetRenderFrameHost(frame_key)); |
lfg
2016/05/13 20:15:40
nit: {}
paulmeyer
2016/05/16 15:25:11
Done.
|
+ } |
+ } |
+ |
+#if defined(OS_ANDROID) |
+ // A reply should not be expected from the removed frame. |
+ RemoveNearestFindResultPendingReply(frame_key); |
+ RemoveFindMatchRectsPendingReply(frame_key); |
+ |
+ // Match rects in the removed frame are no longer relevant. |
+ match_rects_.rects.erase(frame_key); |
+#endif |
+ |
+ // If matches are counted for the frame that is being removed, decrement the |
+ // match total before erasing that entry. |
+ auto it = matches_per_frame_.find(frame_key); |
+ if (it != matches_per_frame_.end()) { |
+ number_of_matches_ -= it->second; |
+ matches_per_frame_.erase(it); |
+ } |
+ |
+ // Update the active match ordinal, since it may have changed. |
+ if (relative_active_match_ordinal_.first == frame_key) { |
+ relative_active_match_ordinal_ = |
+ std::make_pair(std::make_pair(kInvalidId, kInvalidId), 0); |
+ } |
+ UpdateActiveMatchOrdinal(); |
+ |
+ NotifyFindReply(current_session_id_, |
+ pending_replies_.empty() /* final_update */); |
} |
#if defined(OS_ANDROID) |
+FindRequestManager::ActivateNearestFindResultState:: |
+ActivateNearestFindResultState() = default; |
+FindRequestManager::ActivateNearestFindResultState:: |
+ActivateNearestFindResultState(float x, float y) |
+ : current_request_id(GetNextID()), |
+ x(x), |
+ y(y) {} |
+FindRequestManager::ActivateNearestFindResultState:: |
+~ActivateNearestFindResultState() {}; |
+ |
void FindRequestManager::ActivateNearestFindResult(float x, |
float y) { |
if (current_session_id_ == kInvalidId) |
return; |
- auto rfh = contents_->GetMainFrame(); |
- rfh->Send(new InputMsg_ActivateNearestFindResult( |
- rfh->GetRoutingID(), current_session_id_, x, y)); |
+ activate_ = ActivateNearestFindResultState(x, y); |
+ |
+ contents_->ForEachFrame(base::Bind( |
+ &FindRequestManager::SendGetNearestFindResultIPC, |
+ base::Unretained(this))); |
+} |
+ |
+void FindRequestManager::GetNearestFindResultReply(RenderFrameHost* rfh, |
+ int request_id, |
+ float distance) { |
+ FrameKey frame_key = GetFrameKey(rfh); |
+ |
+ if (request_id != activate_.current_request_id || |
+ !activate_.pending_replies.count(frame_key)) { |
+ return; |
+ } |
+ |
+ // Check if this frame has a nearer find result than the current nearest. |
+ if (distance < activate_.nearest_distance) { |
+ activate_.nearest_frame = frame_key; |
+ activate_.nearest_distance = distance; |
+ } |
+ |
+ RemoveNearestFindResultPendingReply(frame_key); |
} |
void FindRequestManager::RequestFindMatchRects(int current_version) { |
+ match_rects_.pending_replies.clear(); |
match_rects_.request_version = current_version; |
- SendFindMatchRectsIPC(contents_->GetMainFrame()); |
+ contents_->ForEachFrame(base::Bind( |
+ &FindRequestManager::SendFindMatchRectsIPC, base::Unretained(this))); |
} |
void FindRequestManager::OnFindMatchRectsReply( |
@@ -94,23 +289,88 @@ void FindRequestManager::OnFindMatchRectsReply( |
int version, |
const std::vector<gfx::RectF>& rects, |
const gfx::RectF& active_rect) { |
- contents_->NotifyFindMatchRectsReply(version, rects, active_rect); |
+ FrameKey frame_key = GetFrameKey(rfh); |
+ auto it = match_rects_.rects.find(frame_key); |
+ if (it == match_rects_.rects.end() || it->second.first != version) { |
+ // New version of rects has been received, so update the data. |
+ match_rects_.rects[frame_key] = std::make_pair(version, rects); |
+ ++match_rects_.known_version; |
+ } |
+ if (!active_rect.IsEmpty()) |
+ match_rects_.active_rect = active_rect; |
+ RemoveFindMatchRectsPendingReply(frame_key); |
} |
#endif |
+void FindRequestManager::RenderFrameDeleted(RenderFrameHost* rfh) { |
+ RemoveFrame(rfh); |
+} |
+ |
+void FindRequestManager::FrameDeleted(RenderFrameHost* rfh) { |
+ RemoveFrame(rfh); |
+} |
+ |
void FindRequestManager::Reset(const FindRequest& initial_request) { |
current_session_id_ = initial_request.id; |
current_request_ = initial_request; |
+ pending_replies_.clear(); |
+ pending_active_match_ordinal_ = initial_request.id; |
+ matches_per_frame_.clear(); |
number_of_matches_ = 0; |
+ relative_active_match_ordinal_ = |
+ std::make_pair(std::make_pair(kInvalidId, kInvalidId), 0); |
active_match_ordinal_ = 0; |
selection_rect_ = gfx::Rect(); |
#if defined(OS_ANDROID) |
- match_rects_ = FindMatchRectsState(); |
+ activate_ = ActivateNearestFindResultState(); |
+ match_rects_.pending_replies.clear(); |
#endif |
} |
+void FindRequestManager::FindInternal(const FindRequest& request) { |
+ DCHECK_GT(request.id, current_request_.id); |
+ DCHECK_GT(request.id, current_session_id_); |
+ |
+ if (request.options.findNext) { |
+ // This is a find next operation. |
+ |
+ // This implies that there is an ongoing find session with the same search |
+ // text. |
+ DCHECK_GE(current_session_id_, 0); |
+ DCHECK_EQ(request.search_text, current_request_.search_text); |
+ |
+ // The find next request will be directed at the focused frame if there is |
+ // one, or the first frame with matches otherwise. |
+ RenderFrameHost* target_rfh = contents_->GetFocusedFrame(); |
+ if (!target_rfh || !CheckFrame(target_rfh)) |
+ target_rfh = GetInitialFrame(request.options.forward); |
+ |
+ SendFindIPC(request, target_rfh); |
+ current_request_ = request; |
+ pending_active_match_ordinal_ = request.id; |
+ return; |
+ } |
+ |
+ // This is an initial find operation. |
+ Reset(request); |
+ contents_->ForEachFrame(base::Bind(&FindRequestManager::AddFrame, |
lfg
2016/05/13 20:15:40
What happens if a frame is created after a find op
paulmeyer
2016/05/16 15:25:11
That is correct, and is the same behavior that fin
lfg
2016/05/16 16:03:29
Acknowledged.
|
+ base::Unretained(this))); |
+} |
+ |
+void FindRequestManager::AdvanceQueue(int request_id) { |
+ if (find_request_queue_.empty() || |
+ request_id != find_request_queue_.front().id) { |
+ return; |
+ } |
+ |
+ find_request_queue_.pop(); |
+ if (!find_request_queue_.empty()) |
+ FindInternal(find_request_queue_.front()); |
+} |
+ |
void FindRequestManager::SendFindIPC(const FindRequest& request, |
RenderFrameHost* rfh) { |
+ pending_replies_.insert(GetFrameKey(rfh)); |
rfh->Send(new FrameMsg_Find(rfh->GetRoutingID(), request.id, |
request.search_text, request.options)); |
} |
@@ -131,10 +391,195 @@ void FindRequestManager::NotifyFindReply(int request_id, |
active_match_ordinal_, final_update); |
} |
+RenderFrameHost* FindRequestManager::GetInitialFrame(bool forward) const { |
+ RenderFrameHost* rfh = contents_->GetMainFrame(); |
+ |
+ if (!forward) |
+ rfh = GetDeepestLastChild(rfh); |
+ |
+ return rfh; |
+} |
+ |
+RenderFrameHost* FindRequestManager::Traverse(RenderFrameHost* rfh, |
+ bool forward, |
+ bool matches_only, |
+ bool wrap) const { |
+ FrameTreeNode* node = |
+ static_cast<RenderFrameHostImpl*>(rfh)->frame_tree_node(); |
+ |
+ while ((node = TraverseNode(node, forward, wrap)) != nullptr) { |
+ if (!CheckFrame(node->current_frame_host())) |
+ continue; |
+ FrameKey frame_key = GetFrameKey(node->current_frame_host()); |
+ if (!matches_only || matches_per_frame_.find(frame_key)->second || |
+ pending_replies_.count(frame_key)) { |
+ // Note that if there is still a pending reply expected for this frame, |
+ // then it may have unaccounted matches and will not be skipped via |
+ // |matches_only|. |
+ return node->current_frame_host(); |
+ } |
+ if (wrap && node->current_frame_host() == rfh) |
+ return nullptr; |
lfg
2016/05/13 20:15:40
Not sure if I follow, shouldn't we return null onl
paulmeyer
2016/05/16 15:25:11
This is just checking for the case where we're wra
lfg
2016/05/16 16:03:29
Acknowledged.
|
+ } |
+ |
+ return nullptr; |
+} |
+ |
+void FindRequestManager::AddFrame(RenderFrameHost* rfh) { |
+ FrameKey frame_key = GetFrameKey(rfh); |
+ // A frame that is already being searched should not be added again. |
+ DCHECK(!CheckFrame(frame_key)); |
+ |
+ matches_per_frame_[frame_key] = 0; |
+ |
+ FindRequest request = current_request_; |
+ request.id = current_session_id_; |
+ request.options.findNext = false; |
+ SendFindIPC(request, rfh); |
+} |
+ |
+bool FindRequestManager::CheckFrame(RenderFrameHost* rfh) const { |
+ return rfh ? CheckFrame(GetFrameKey(rfh)) : false; |
+} |
+ |
+bool FindRequestManager::CheckFrame(const FrameKey& frame_key) const { |
+ return matches_per_frame_.count(frame_key) == 1; |
+} |
+ |
+void FindRequestManager::UpdateActiveMatchOrdinal() { |
+ if (relative_active_match_ordinal_.first.first == kInvalidId || |
+ relative_active_match_ordinal_.first.second == kInvalidId || |
+ relative_active_match_ordinal_.second == 0) { |
+ active_match_ordinal_ = 0; |
+ return; |
+ } |
+ |
+ RenderFrameHost* rfh = |
+ GetRenderFrameHost(relative_active_match_ordinal_.first); |
+ if (!rfh) { |
+ RemoveFrame(relative_active_match_ordinal_.first); |
+ active_match_ordinal_ = 0; |
+ return; |
+ } |
+ |
+ // Traverse the frame tree backwards (in search order) and count all of the |
+ // matches in frames before the frame with the active match, in order to |
+ // determine the overall active match ordinal. |
+ active_match_ordinal_ = 0; |
+ while ((rfh = Traverse(rfh, |
+ false /* forward */, |
+ true /* matches_only */, |
+ false /* wrap */)) != nullptr) { |
+ active_match_ordinal_ += matches_per_frame_[GetFrameKey(rfh)]; |
+ } |
+ active_match_ordinal_ += relative_active_match_ordinal_.second; |
+} |
+ |
+void FindRequestManager::FinalUpdate(int request_id, RenderFrameHost* rfh) { |
+ if (!number_of_matches_ || pending_active_match_ordinal_ != request_id) { |
+ NotifyFindReply(request_id, true /* final_update */); |
+ AdvanceQueue(request_id); |
+ return; |
+ } |
+ |
+ // There are matches, but no active match was returned, so another find next |
+ // request must be sent. |
+ |
+ DCHECK_EQ(request_id, current_request_.id); |
+ RenderFrameHost* target_rfh; |
+ if (current_request_.options.findNext) { |
+ // If this was a find next operation, then the active match will be in the |
+ // next frame with matches after this one. |
+ target_rfh = Traverse(static_cast<RenderFrameHostImpl*>(rfh), |
+ current_request_.options.forward, |
+ true /* matches_only */, |
+ true /* wrap */); |
+ } else if ((target_rfh = contents_->GetFocusedFrame()) != nullptr) { |
+ // Otherwise, if there is a focused frame, then the active match will be in |
+ // the next frame with matches after that one. |
+ target_rfh = Traverse(target_rfh, |
+ current_request_.options.forward, |
+ true /* matches_only */, |
+ true /* wrap */); |
+ } else { |
+ // Otherwise, the first frame with matches will have the active match. |
+ target_rfh = GetInitialFrame(current_request_.options.forward); |
+ if (!CheckFrame(target_rfh) || |
+ !matches_per_frame_[GetFrameKey(target_rfh)]) { |
+ target_rfh = Traverse(target_rfh, |
+ current_request_.options.forward, |
+ true /* matches_only */, |
+ false /* wrap */); |
+ } |
+ } |
+ DCHECK(target_rfh); |
+ |
+ // Forward the find reply without |final_update| set because the active match |
+ // has not yet been found. |
+ NotifyFindReply(request_id, false /* final_update */); |
+ |
+ current_request_.options.findNext = true; |
+ SendFindIPC(current_request_, target_rfh); |
+} |
+ |
#if defined(OS_ANDROID) |
+void FindRequestManager::SendGetNearestFindResultIPC(RenderFrameHost* rfh) { |
+ FrameKey frame_key = GetFrameKey(rfh); |
+ if (!CheckFrame(frame_key)) |
+ return; |
+ |
+ activate_.pending_replies.insert(GetFrameKey(rfh)); |
+ rfh->Send(new FrameMsg_GetNearestFindResult( |
+ rfh->GetRoutingID(), activate_.current_request_id, |
+ activate_.x, activate_.y)); |
+} |
+ |
+void FindRequestManager::RemoveNearestFindResultPendingReply( |
+ FrameKey frame_key) { |
+ auto it = activate_.pending_replies.find(frame_key); |
+ if (it != activate_.pending_replies.end()) { |
+ activate_.pending_replies.erase(it); |
+ if (activate_.pending_replies.empty() && |
+ CheckFrame(activate_.nearest_frame)) { |
+ RenderFrameHostImpl* rfh = GetRenderFrameHost(activate_.nearest_frame); |
+ rfh->Send(new FrameMsg_ActivateNearestFindResult( |
+ rfh->GetRoutingID(), current_session_id_, activate_.x, activate_.y)); |
+ } |
+ } |
+} |
+ |
void FindRequestManager::SendFindMatchRectsIPC(RenderFrameHost* rfh) { |
- rfh->Send(new FrameMsg_FindMatchRects(rfh->GetRoutingID(), |
- match_rects_.request_version)); |
+ FrameKey frame_key = GetFrameKey(rfh); |
+ if (!CheckFrame(frame_key)) |
+ return; |
+ |
+ match_rects_.pending_replies.insert(frame_key); |
+ auto it = match_rects_.rects.find(frame_key); |
+ int version = |
+ (it != match_rects_.rects.end()) ? it->second.first : kInvalidId; |
+ rfh->Send(new FrameMsg_FindMatchRects(rfh->GetRoutingID(), version)); |
+} |
+ |
+void FindRequestManager::RemoveFindMatchRectsPendingReply(FrameKey frame_key) { |
+ auto it = match_rects_.pending_replies.find(frame_key); |
+ if (it == match_rects_.pending_replies.end()) |
+ return; |
+ |
+ match_rects_.pending_replies.erase(it); |
+ if (match_rects_.pending_replies.empty()) { |
+ // All replies are in. |
+ std::vector<gfx::RectF> rects; |
+ if (match_rects_.request_version != match_rects_.known_version) { |
+ // Request version is stale, so aggregate and report the newer find |
+ // match rects. |
+ for (auto& entry : match_rects_.rects) { |
+ std::vector<gfx::RectF>& frame_rects = entry.second.second; |
+ rects.insert(rects.end(), frame_rects.begin(), frame_rects.end()); |
+ } |
+ } |
+ contents_->NotifyFindMatchRectsReply( |
+ match_rects_.known_version, rects, match_rects_.active_rect); |
+ } |
} |
#endif |