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