Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(648)

Side by Side Diff: content/browser/find_request_manager.cc

Issue 1959183002: Multi-Process Find-in-Page. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Addressed comments by dcheng@. Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/browser/find_request_manager.h" 5 #include "content/browser/find_request_manager.h"
6 6
7 #include "content/browser/frame_host/render_frame_host_impl.h" 7 #include "content/browser/frame_host/render_frame_host_impl.h"
8 #include "content/browser/web_contents/web_contents_impl.h" 8 #include "content/browser/web_contents/web_contents_impl.h"
9 #include "content/common/frame_messages.h" 9 #include "content/common/frame_messages.h"
10 #include "content/common/input_messages.h" 10 #include "content/common/input_messages.h"
11 11
12 namespace content { 12 namespace content {
13 13
14 namespace {
15
16 // Returns the key for the frame associated with |rfh|.
17 FindRequestManager::FrameKey GetFrameKey(RenderFrameHost* rfh) {
18 return std::make_pair(rfh->GetProcess()->GetID(), rfh->GetRoutingID());
19 }
20
21 // Returns the RenderFrameHostImpl associated with |frame_key|.
22 RenderFrameHostImpl* GetRenderFrameHost(
23 const FindRequestManager::FrameKey& frame_key) {
24 return RenderFrameHostImpl::FromID(frame_key.first, frame_key.second);
25 }
26
27 // Returns the deepest last child frame under |node|/|rfh| in the frame tree.
28 FrameTreeNode* GetDeepestLastChild(FrameTreeNode* node) {
29 while (node->child_count())
30 node = node->child_at(node->child_count() - 1);
31 return node;
32 }
33 RenderFrameHost* GetDeepestLastChild(RenderFrameHost* rfh) {
34 FrameTreeNode* node =
35 static_cast<RenderFrameHostImpl*>(rfh)->frame_tree_node();
36 return GetDeepestLastChild(node)->current_frame_host();
37 }
38
39 // Returns the FrameTreeNode directly after |node| in the frame tree in search
40 // order, or nullptr if one does not exist. If |wrap| is set, then wrapping
41 // between the first and last frames is permitted. Note that this traversal
42 // follows the same ordering as in blink::FrameTree::traverseNextWithWrap().
43 FrameTreeNode* TraverseNext(FrameTreeNode* node, bool wrap) {
44 if (node->child_count())
45 return node->child_at(0);
46
47 FrameTreeNode* sibling = node->NextSibling();
48 while (!sibling) {
49 if (!node->parent())
50 return wrap ? node : nullptr;
51 node = node->parent();
52 sibling = node->NextSibling();
53 }
54 return sibling;
55 }
56
57 // Returns the FrameTreeNode directly before |node| in the frame tree in search
58 // order, or nullptr if one does not exist. If |wrap| is set, then wrapping
59 // between the first and last frames is permitted. Note that this traversal
60 // follows the same ordering as in blink::FrameTree::traversePreviousWithWrap().
61 FrameTreeNode* TraversePrevious(FrameTreeNode* node, bool wrap) {
62 if (FrameTreeNode* previous_sibling = node->PreviousSibling())
63 return GetDeepestLastChild(previous_sibling);
64 if (node->parent())
65 return node->parent();
66 return wrap ? GetDeepestLastChild(node) : nullptr;
67 }
68
69 // The same as either TraverseNext() or TraversePrevious() depending on
70 // |forward|.
71 FrameTreeNode* TraverseNode(FrameTreeNode* node, bool forward, bool wrap) {
72 return forward ? TraverseNext(node, wrap) : TraversePrevious(node, wrap);
73 }
ncarter (slow) 2016/05/23 21:59:16 Could you move these to FrameTree or FrameTreeNode
paulmeyer 2016/05/30 15:08:22 As discussed offline, I can look into moving these
74
75 } // namespace
76
77 #if defined(OS_ANDROID)
78 FindRequestManager::FindMatchRectsState::FindMatchRectsState() = default;
79 FindRequestManager::FindMatchRectsState::~FindMatchRectsState() {}
80 #endif
81
14 // static 82 // static
15 const int FindRequestManager::kInvalidId = -1; 83 const int FindRequestManager::kInvalidId = -1;
16 84
17 FindRequestManager::FindRequestManager(WebContentsImpl* web_contents) 85 FindRequestManager::FindRequestManager(WebContentsImpl* web_contents)
18 : contents_(web_contents), 86 : WebContentsObserver(web_contents),
87 contents_(web_contents),
19 current_session_id_(kInvalidId), 88 current_session_id_(kInvalidId),
89 pending_active_match_ordinal_(kInvalidId),
20 number_of_matches_(0), 90 number_of_matches_(0),
91 relative_active_match_ordinal_(
92 std::make_pair(std::make_pair(kInvalidId, kInvalidId), 0)),
21 active_match_ordinal_(0) {} 93 active_match_ordinal_(0) {}
22 94
23 FindRequestManager::~FindRequestManager() {} 95 FindRequestManager::~FindRequestManager() {}
24 96
25 void FindRequestManager::Find(int request_id, 97 void FindRequestManager::Find(int request_id,
26 const base::string16& search_text, 98 const base::string16& search_text,
27 const blink::WebFindOptions& options) { 99 const blink::WebFindOptions& options) {
28 // Every find request must have a unique ID, and these IDs must strictly 100 // Every find request must have a unique ID, and these IDs must strictly
29 // increase so that newer requests always have greater IDs than older 101 // increase so that newer requests always have greater IDs than older
30 // requests. 102 // requests.
31 DCHECK_GT(request_id, current_request_.id); 103 DCHECK_GT(request_id, current_request_.id);
32 DCHECK_GT(request_id, current_session_id_); 104 DCHECK_GT(request_id, current_session_id_);
33 105
34 FindRequest request(request_id, search_text, options); 106 // If this is a new find session, clear any queued requests from last session.
35 107 if (!options.findNext) {
36 if (options.findNext) { 108 find_request_queue_ = std::queue<FindRequest>();
37 // This is a find next operation.
38
39 // This implies that there is an ongoing find session with the same search
40 // text.
41 DCHECK_GE(current_session_id_, 0);
42 DCHECK_EQ(request.search_text, current_request_.search_text);
43
44 current_request_ = request;
45 } else {
46 // This is an initial find operation.
47 Reset(request);
48 } 109 }
49 110
50 SendFindIPC(request, contents_->GetMainFrame()); 111 find_request_queue_.emplace(request_id, search_text, options);
112 if (find_request_queue_.size() == 1)
113 FindInternal(find_request_queue_.front());
51 } 114 }
52 115
53 void FindRequestManager::StopFinding(StopFindAction action) { 116 void FindRequestManager::StopFinding(StopFindAction action) {
54 SendStopFindingIPC(action, contents_->GetMainFrame()); 117 contents_->ForEachFrame(base::Bind(
ncarter (slow) 2016/05/23 21:59:16 We should skip !IsRenderFrameLive() frames. SendT
paulmeyer 2016/05/30 15:08:22 I'll just use SendToAllFrames in this case.
118 &FindRequestManager::SendStopFindingIPC, base::Unretained(this), action));
55 current_session_id_ = kInvalidId; 119 current_session_id_ = kInvalidId;
120 #if defined(OS_ANDROID)
121 // It is important that these pending replies are cleared whenever a find
122 // session ends, so that subsequent replies for the old session are ignored.
123 match_rects_.pending_replies.clear();
124 #endif
56 } 125 }
57 126
58 void FindRequestManager::OnFindReply(RenderFrameHost* rfh, 127 void FindRequestManager::OnFindReply(RenderFrameHost* rfh,
59 int request_id, 128 int request_id,
60 int number_of_matches, 129 int number_of_matches,
61 const gfx::Rect& selection_rect, 130 const gfx::Rect& selection_rect,
62 int active_match_ordinal, 131 int active_match_ordinal,
63 bool final_update) { 132 bool final_update) {
64 // Ignore stale replies from abandoned find sessions. 133 // Ignore stale replies from abandoned find sessions.
65 if (current_session_id_ == kInvalidId || request_id < current_session_id_) 134 if (current_session_id_ == kInvalidId || request_id < current_session_id_)
66 return; 135 return;
136 DCHECK(CheckFrame(rfh));
137
138 FrameKey frame_key = GetFrameKey(rfh);
67 139
68 // Update the stored results. 140 // Update the stored results.
69 number_of_matches_ = number_of_matches; 141 if (number_of_matches != -1) {
ncarter (slow) 2016/05/23 21:59:16 This use of sentinel values makes me wonder if we
paulmeyer 2016/05/30 15:08:22 As discussed offline, splitting this IPC may not m
70 selection_rect_ = selection_rect; 142 DCHECK_GE(number_of_matches, 0);
71 active_match_ordinal_ = active_match_ordinal; 143 // Increment the global number of matches by the number of additional
144 // matches found for this frame.
145 auto matches_per_frame_it = matches_per_frame_.find(frame_key);
146 number_of_matches_ += number_of_matches - matches_per_frame_it->second;
147 matches_per_frame_it->second = number_of_matches;
148 }
149 if (!selection_rect.IsEmpty())
150 selection_rect_ = selection_rect;
151 if (active_match_ordinal > 0) {
ncarter (slow) 2016/05/23 21:59:16 Could we rename either active_match_ordinal or act
paulmeyer 2016/05/30 15:08:22 I'd actually really rather keep them the way they
152 if (GetFrameKey(rfh) == relative_active_match_ordinal_.first) {
153 active_match_ordinal_ +=
154 active_match_ordinal - relative_active_match_ordinal_.second;
ncarter (slow) 2016/05/23 21:59:16 is the value of "(active_match_ordinal - relative_
paulmeyer 2016/05/30 15:08:22 No, it could be any arbitrary int. In a large fram
155 relative_active_match_ordinal_.second = active_match_ordinal;
156 } else {
157 if (relative_active_match_ordinal_.first.first != kInvalidId) {
158 RenderFrameHost* old_rfh =
159 GetRenderFrameHost(relative_active_match_ordinal_.first);
160 if (old_rfh && old_rfh != rfh) {
ncarter (slow) 2016/05/23 21:59:16 the != case here is impossible. We already checked
paulmeyer 2016/05/30 15:08:22 Okay, you're right. I can just take out these cond
161 old_rfh->Send(new FrameMsg_ClearActiveFindMatch(
162 old_rfh->GetRoutingID()));
163 }
164 }
165 relative_active_match_ordinal_ =
166 std::make_pair(GetFrameKey(rfh), active_match_ordinal);
167 UpdateActiveMatchOrdinal();
168 }
169 if (pending_active_match_ordinal_ == request_id)
170 pending_active_match_ordinal_ = kInvalidId;
171 AdvanceQueue(request_id);
172 }
ncarter (slow) 2016/05/23 21:59:16 Looking at this function, I wondered: what if we t
paulmeyer 2016/05/30 15:08:22 That case involves dynamically changing content (s
72 173
ncarter (slow) 2016/05/23 21:59:16 Possibly related to the previous comment: In a deb
paulmeyer 2016/05/30 15:08:22 I was able to repro this. It's this DCHECK in Docu
73 NotifyFindReply(request_id, final_update); 174 if (!final_update) {
175 NotifyFindReply(request_id, false /* final_update */);
176 return;
177 }
178
179 // This is the final update for this frame for the current find operation.
180
181 pending_replies_.erase(frame_key);
182 if (request_id == current_session_id_ && !pending_replies_.empty()) {
183 NotifyFindReply(request_id, false /* final_update */);
184 return;
185 }
186 DCHECK(request_id == current_session_id_ ||
187 current_request_.options.findNext);
188
189 // This is the final update for the current find operation.
190 FinalUpdate(request_id, rfh);
191 }
192
193 void FindRequestManager::RemoveFrame(RenderFrameHost* rfh) {
194 RemoveFrame(GetFrameKey(rfh));
195 }
196
197 void FindRequestManager::RemoveFrame(const FrameKey& frame_key) {
198 if (current_session_id_ == kInvalidId || !CheckFrame(frame_key))
199 return;
200
201 if (pending_replies_.count(frame_key)) {
202 // A reply should not be expected from the removed frame.
203 pending_replies_.erase(frame_key);
204 if (pending_replies_.empty())
205 FinalUpdate(current_session_id_, GetRenderFrameHost(frame_key));
206 }
207
208 #if defined(OS_ANDROID)
209 // A reply should not be expected from the removed frame.
210 RemoveNearestFindResultPendingReply(frame_key);
211 RemoveFindMatchRectsPendingReply(frame_key);
212
213 // Match rects in the removed frame are no longer relevant.
214 match_rects_.rects.erase(frame_key);
215 #endif
216
217 // If matches are counted for the frame that is being removed, decrement the
218 // match total before erasing that entry.
219 auto it = matches_per_frame_.find(frame_key);
220 if (it != matches_per_frame_.end()) {
221 number_of_matches_ -= it->second;
222 matches_per_frame_.erase(it);
223 }
224
225 // Update the active match ordinal, since it may have changed.
226 if (relative_active_match_ordinal_.first == frame_key) {
227 relative_active_match_ordinal_ =
228 std::make_pair(std::make_pair(kInvalidId, kInvalidId), 0);
229 }
230 UpdateActiveMatchOrdinal();
231
232 NotifyFindReply(current_session_id_,
233 pending_replies_.empty() /* final_update */);
74 } 234 }
75 235
76 #if defined(OS_ANDROID) 236 #if defined(OS_ANDROID)
237 FindRequestManager::ActivateNearestFindResultState::
238 ActivateNearestFindResultState() = default;
239 FindRequestManager::ActivateNearestFindResultState::
240 ActivateNearestFindResultState(float x, float y)
241 : current_request_id(GetNextID()),
242 x(x),
243 y(y) {}
244 FindRequestManager::ActivateNearestFindResultState::
245 ~ActivateNearestFindResultState() {};
246
77 void FindRequestManager::ActivateNearestFindResult(float x, 247 void FindRequestManager::ActivateNearestFindResult(float x,
78 float y) { 248 float y) {
79 if (current_session_id_ == kInvalidId) 249 if (current_session_id_ == kInvalidId)
80 return; 250 return;
81 251
82 auto rfh = contents_->GetMainFrame(); 252 activate_ = ActivateNearestFindResultState(x, y);
83 rfh->Send(new InputMsg_ActivateNearestFindResult( 253
84 rfh->GetRoutingID(), current_session_id_, x, y)); 254 contents_->ForEachFrame(base::Bind(
ncarter (slow) 2016/05/23 21:59:16 We should skip !IsRenderFrameLive() frames. SendT
paulmeyer 2016/05/30 15:08:22 I've removed SendGetNearestFindResultIPC() and jus
255 &FindRequestManager::SendGetNearestFindResultIPC,
256 base::Unretained(this)));
257 }
258
259 void FindRequestManager::GetNearestFindResultReply(RenderFrameHost* rfh,
260 int request_id,
261 float distance) {
262 FrameKey frame_key = GetFrameKey(rfh);
263
264 if (request_id != activate_.current_request_id ||
265 !activate_.pending_replies.count(frame_key)) {
266 return;
267 }
268
269 // Check if this frame has a nearer find result than the current nearest.
270 if (distance < activate_.nearest_distance) {
271 activate_.nearest_frame = frame_key;
272 activate_.nearest_distance = distance;
273 }
274
275 RemoveNearestFindResultPendingReply(frame_key);
85 } 276 }
86 277
87 void FindRequestManager::RequestFindMatchRects(int current_version) { 278 void FindRequestManager::RequestFindMatchRects(int current_version) {
279 match_rects_.pending_replies.clear();
88 match_rects_.request_version = current_version; 280 match_rects_.request_version = current_version;
89 SendFindMatchRectsIPC(contents_->GetMainFrame()); 281 contents_->ForEachFrame(base::Bind(
ncarter (slow) 2016/05/23 21:59:16 We should skip !IsRenderFrameLive() frames. SendT
paulmeyer 2016/05/30 15:08:22 I've removed SendFindMatchRectsIPC(). I'll just do
282 &FindRequestManager::SendFindMatchRectsIPC, base::Unretained(this)));
90 } 283 }
91 284
92 void FindRequestManager::OnFindMatchRectsReply( 285 void FindRequestManager::OnFindMatchRectsReply(
93 RenderFrameHost* rfh, 286 RenderFrameHost* rfh,
94 int version, 287 int version,
95 const std::vector<gfx::RectF>& rects, 288 const std::vector<gfx::RectF>& rects,
96 const gfx::RectF& active_rect) { 289 const gfx::RectF& active_rect) {
97 contents_->NotifyFindMatchRectsReply(version, rects, active_rect); 290 FrameKey frame_key = GetFrameKey(rfh);
291 auto it = match_rects_.rects.find(frame_key);
292 if (it == match_rects_.rects.end() || it->second.first != version) {
293 // New version of rects has been received, so update the data.
294 match_rects_.rects[frame_key] = std::make_pair(version, rects);
295 ++match_rects_.known_version;
296 }
297 if (!active_rect.IsEmpty())
298 match_rects_.active_rect = active_rect;
299 RemoveFindMatchRectsPendingReply(frame_key);
98 } 300 }
99 #endif 301 #endif
100 302
303 void FindRequestManager::RenderFrameDeleted(RenderFrameHost* rfh) {
304 RemoveFrame(rfh);
305 }
306
307 void FindRequestManager::FrameDeleted(RenderFrameHost* rfh) {
ncarter (slow) 2016/05/23 21:59:16 Usually if you care about FrameDeleted (which is w
paulmeyer 2016/05/30 15:08:23 I wasn't aware of that case; thanks for catching t
308 RemoveFrame(rfh);
309 }
ncarter (slow) 2016/05/23 21:59:16 Based on my manual testing of this patch, it seems
paulmeyer 2016/05/30 15:08:22 For the first case: As a kind of dynamic content
paulmeyer 2016/05/31 14:32:38 More info about second case: This actually isn't a
310
101 void FindRequestManager::Reset(const FindRequest& initial_request) { 311 void FindRequestManager::Reset(const FindRequest& initial_request) {
102 current_session_id_ = initial_request.id; 312 current_session_id_ = initial_request.id;
103 current_request_ = initial_request; 313 current_request_ = initial_request;
314 pending_replies_.clear();
315 pending_active_match_ordinal_ = initial_request.id;
316 matches_per_frame_.clear();
104 number_of_matches_ = 0; 317 number_of_matches_ = 0;
318 relative_active_match_ordinal_ =
319 std::make_pair(std::make_pair(kInvalidId, kInvalidId), 0);
105 active_match_ordinal_ = 0; 320 active_match_ordinal_ = 0;
106 selection_rect_ = gfx::Rect(); 321 selection_rect_ = gfx::Rect();
107 #if defined(OS_ANDROID) 322 #if defined(OS_ANDROID)
108 match_rects_ = FindMatchRectsState(); 323 activate_ = ActivateNearestFindResultState();
324 match_rects_.pending_replies.clear();
109 #endif 325 #endif
110 } 326 }
111 327
328 void FindRequestManager::FindInternal(const FindRequest& request) {
329 DCHECK_GT(request.id, current_request_.id);
330 DCHECK_GT(request.id, current_session_id_);
331
332 if (request.options.findNext) {
333 // This is a find next operation.
334
335 // This implies that there is an ongoing find session with the same search
336 // text.
337 DCHECK_GE(current_session_id_, 0);
338 DCHECK_EQ(request.search_text, current_request_.search_text);
339
340 // The find next request will be directed at the focused frame if there is
341 // one, or the first frame with matches otherwise.
342 RenderFrameHost* target_rfh = contents_->GetFocusedFrame();
343 if (!target_rfh || !CheckFrame(target_rfh))
344 target_rfh = GetInitialFrame(request.options.forward);
345
346 SendFindIPC(request, target_rfh);
347 current_request_ = request;
348 pending_active_match_ordinal_ = request.id;
349 return;
350 }
351
352 // This is an initial find operation.
353 Reset(request);
354 contents_->ForEachFrame(base::Bind(&FindRequestManager::AddFrame,
ncarter (slow) 2016/05/23 21:59:16 We should skip !IsRenderFrameLive() frames. You c
paulmeyer 2016/05/30 15:08:23 I'll use a loop over FrameTree::Nodes() here too.
355 base::Unretained(this)));
356 }
357
358 void FindRequestManager::AdvanceQueue(int request_id) {
359 if (find_request_queue_.empty() ||
360 request_id != find_request_queue_.front().id) {
361 return;
362 }
363
364 find_request_queue_.pop();
365 if (!find_request_queue_.empty())
366 FindInternal(find_request_queue_.front());
367 }
368
112 void FindRequestManager::SendFindIPC(const FindRequest& request, 369 void FindRequestManager::SendFindIPC(const FindRequest& request,
113 RenderFrameHost* rfh) { 370 RenderFrameHost* rfh) {
371 pending_replies_.insert(GetFrameKey(rfh));
114 rfh->Send(new FrameMsg_Find(rfh->GetRoutingID(), request.id, 372 rfh->Send(new FrameMsg_Find(rfh->GetRoutingID(), request.id,
115 request.search_text, request.options)); 373 request.search_text, request.options));
116 } 374 }
117 375
118 void FindRequestManager::SendStopFindingIPC(StopFindAction action, 376 void FindRequestManager::SendStopFindingIPC(StopFindAction action,
119 RenderFrameHost* rfh) const { 377 RenderFrameHost* rfh) const {
120 rfh->Send(new FrameMsg_StopFinding(rfh->GetRoutingID(), action)); 378 rfh->Send(new FrameMsg_StopFinding(rfh->GetRoutingID(), action));
121 } 379 }
122 380
123 void FindRequestManager::NotifyFindReply(int request_id, 381 void FindRequestManager::NotifyFindReply(int request_id,
124 bool final_update) const { 382 bool final_update) const {
125 if (request_id == kInvalidId) { 383 if (request_id == kInvalidId) {
126 NOTREACHED(); 384 NOTREACHED();
127 return; 385 return;
128 } 386 }
129 387
130 contents_->NotifyFindReply(request_id, number_of_matches_, selection_rect_, 388 contents_->NotifyFindReply(request_id, number_of_matches_, selection_rect_,
131 active_match_ordinal_, final_update); 389 active_match_ordinal_, final_update);
132 } 390 }
133 391
392 RenderFrameHost* FindRequestManager::GetInitialFrame(bool forward) const {
393 RenderFrameHost* rfh = contents_->GetMainFrame();
394
395 if (!forward)
396 rfh = GetDeepestLastChild(rfh);
397
398 return rfh;
399 }
400
401 RenderFrameHost* FindRequestManager::Traverse(RenderFrameHost* rfh,
402 bool forward,
403 bool matches_only,
404 bool wrap) const {
405 FrameTreeNode* node =
406 static_cast<RenderFrameHostImpl*>(rfh)->frame_tree_node();
407
408 while ((node = TraverseNode(node, forward, wrap)) != nullptr) {
409 if (!CheckFrame(node->current_frame_host()))
410 continue;
411 FrameKey frame_key = GetFrameKey(node->current_frame_host());
412 if (!matches_only || matches_per_frame_.find(frame_key)->second ||
413 pending_replies_.count(frame_key)) {
414 // Note that if there is still a pending reply expected for this frame,
415 // then it may have unaccounted matches and will not be skipped via
416 // |matches_only|.
417 return node->current_frame_host();
418 }
419 if (wrap && node->current_frame_host() == rfh)
420 return nullptr;
421 }
422
423 return nullptr;
424 }
425
426 void FindRequestManager::AddFrame(RenderFrameHost* rfh) {
427 FrameKey frame_key = GetFrameKey(rfh);
428 // A frame that is already being searched should not be added again.
429 DCHECK(!CheckFrame(frame_key));
430
431 matches_per_frame_[frame_key] = 0;
432
433 FindRequest request = current_request_;
434 request.id = current_session_id_;
435 request.options.findNext = false;
436 SendFindIPC(request, rfh);
437 }
438
439 bool FindRequestManager::CheckFrame(RenderFrameHost* rfh) const {
440 return rfh ? CheckFrame(GetFrameKey(rfh)) : false;
441 }
442
443 bool FindRequestManager::CheckFrame(const FrameKey& frame_key) const {
444 return matches_per_frame_.count(frame_key) == 1;
445 }
446
447 void FindRequestManager::UpdateActiveMatchOrdinal() {
448 if (relative_active_match_ordinal_.first.first == kInvalidId ||
449 relative_active_match_ordinal_.first.second == kInvalidId ||
450 relative_active_match_ordinal_.second == 0) {
451 active_match_ordinal_ = 0;
452 return;
453 }
454
455 RenderFrameHost* rfh =
456 GetRenderFrameHost(relative_active_match_ordinal_.first);
457 if (!rfh) {
458 RemoveFrame(relative_active_match_ordinal_.first);
459 active_match_ordinal_ = 0;
460 return;
461 }
462
463 // Traverse the frame tree backwards (in search order) and count all of the
464 // matches in frames before the frame with the active match, in order to
465 // determine the overall active match ordinal.
466 active_match_ordinal_ = 0;
467 while ((rfh = Traverse(rfh,
468 false /* forward */,
469 true /* matches_only */,
470 false /* wrap */)) != nullptr) {
471 active_match_ordinal_ += matches_per_frame_[GetFrameKey(rfh)];
472 }
473 active_match_ordinal_ += relative_active_match_ordinal_.second;
474 }
475
476 void FindRequestManager::FinalUpdate(int request_id, RenderFrameHost* rfh) {
477 if (!number_of_matches_ || pending_active_match_ordinal_ != request_id) {
478 NotifyFindReply(request_id, true /* final_update */);
479 AdvanceQueue(request_id);
480 return;
481 }
482
483 // There are matches, but no active match was returned, so another find next
484 // request must be sent.
485
486 DCHECK_EQ(request_id, current_request_.id);
487 RenderFrameHost* target_rfh;
488 if (current_request_.options.findNext) {
489 // If this was a find next operation, then the active match will be in the
490 // next frame with matches after this one.
491 target_rfh = Traverse(static_cast<RenderFrameHostImpl*>(rfh),
492 current_request_.options.forward,
493 true /* matches_only */,
494 true /* wrap */);
495 } else if ((target_rfh = contents_->GetFocusedFrame()) != nullptr) {
496 // Otherwise, if there is a focused frame, then the active match will be in
497 // the next frame with matches after that one.
498 target_rfh = Traverse(target_rfh,
499 current_request_.options.forward,
500 true /* matches_only */,
501 true /* wrap */);
502 } else {
503 // Otherwise, the first frame with matches will have the active match.
504 target_rfh = GetInitialFrame(current_request_.options.forward);
505 if (!CheckFrame(target_rfh) ||
506 !matches_per_frame_[GetFrameKey(target_rfh)]) {
507 target_rfh = Traverse(target_rfh,
508 current_request_.options.forward,
509 true /* matches_only */,
510 false /* wrap */);
511 }
512 }
513 DCHECK(target_rfh);
514
515 // Forward the find reply without |final_update| set because the active match
516 // has not yet been found.
517 NotifyFindReply(request_id, false /* final_update */);
518
519 current_request_.options.findNext = true;
520 SendFindIPC(current_request_, target_rfh);
521 }
522
134 #if defined(OS_ANDROID) 523 #if defined(OS_ANDROID)
524 void FindRequestManager::SendGetNearestFindResultIPC(RenderFrameHost* rfh) {
525 FrameKey frame_key = GetFrameKey(rfh);
526 if (!CheckFrame(frame_key))
527 return;
528
529 activate_.pending_replies.insert(GetFrameKey(rfh));
530 rfh->Send(new FrameMsg_GetNearestFindResult(
531 rfh->GetRoutingID(), activate_.current_request_id,
532 activate_.x, activate_.y));
533 }
534
535 void FindRequestManager::RemoveNearestFindResultPendingReply(
536 FrameKey frame_key) {
537 auto it = activate_.pending_replies.find(frame_key);
538 if (it != activate_.pending_replies.end()) {
539 activate_.pending_replies.erase(it);
540 if (activate_.pending_replies.empty() &&
541 CheckFrame(activate_.nearest_frame)) {
542 RenderFrameHostImpl* rfh = GetRenderFrameHost(activate_.nearest_frame);
543 rfh->Send(new FrameMsg_ActivateNearestFindResult(
544 rfh->GetRoutingID(), current_session_id_, activate_.x, activate_.y));
545 }
546 }
547 }
548
135 void FindRequestManager::SendFindMatchRectsIPC(RenderFrameHost* rfh) { 549 void FindRequestManager::SendFindMatchRectsIPC(RenderFrameHost* rfh) {
136 rfh->Send(new FrameMsg_FindMatchRects(rfh->GetRoutingID(), 550 FrameKey frame_key = GetFrameKey(rfh);
137 match_rects_.request_version)); 551 if (!CheckFrame(frame_key))
552 return;
553
554 match_rects_.pending_replies.insert(frame_key);
555 auto it = match_rects_.rects.find(frame_key);
556 int version =
557 (it != match_rects_.rects.end()) ? it->second.first : kInvalidId;
558 rfh->Send(new FrameMsg_FindMatchRects(rfh->GetRoutingID(), version));
559 }
560
561 void FindRequestManager::RemoveFindMatchRectsPendingReply(FrameKey frame_key) {
562 auto it = match_rects_.pending_replies.find(frame_key);
563 if (it == match_rects_.pending_replies.end())
564 return;
565
566 match_rects_.pending_replies.erase(it);
567 if (match_rects_.pending_replies.empty()) {
568 // All replies are in.
569 std::vector<gfx::RectF> rects;
570 if (match_rects_.request_version != match_rects_.known_version) {
571 // Request version is stale, so aggregate and report the newer find
572 // match rects.
573 for (auto& entry : match_rects_.rects) {
574 std::vector<gfx::RectF>& frame_rects = entry.second.second;
575 rects.insert(rects.end(), frame_rects.begin(), frame_rects.end());
576 }
577 }
578 contents_->NotifyFindMatchRectsReply(
579 match_rects_.known_version, rects, match_rects_.active_rect);
580 }
138 } 581 }
139 #endif 582 #endif
140 583
141 } // namespace content 584 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698