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) { | |
dglazkov
2016/06/02 04:48:57
Can this live in some common FrameTreeNode place?
paulmeyer
2016/06/02 17:36:36
Yeah, it can, and I agree that it should.
I had a
| |
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. |
112 if (!options.findNext) | |
113 find_request_queue_ = std::queue<FindRequest>(); | |
35 | 114 |
36 if (options.findNext) { | 115 find_request_queue_.emplace(request_id, search_text, options); |
37 // This is a find next operation. | 116 if (find_request_queue_.size() == 1) |
38 | 117 FindInternal(find_request_queue_.front()); |
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 } | |
49 | |
50 SendFindIPC(request, contents_->GetMainFrame()); | |
51 } | 118 } |
52 | 119 |
53 void FindRequestManager::StopFinding(StopFindAction action) { | 120 void FindRequestManager::StopFinding(StopFindAction action) { |
54 SendStopFindingIPC(action, contents_->GetMainFrame()); | 121 contents_->SendToAllFrames( |
122 new FrameMsg_StopFinding(MSG_ROUTING_NONE, action)); | |
123 | |
55 current_session_id_ = kInvalidId; | 124 current_session_id_ = kInvalidId; |
125 #if defined(OS_ANDROID) | |
126 // It is important that these pending replies are cleared whenever a find | |
127 // session ends, so that subsequent replies for the old session are ignored. | |
128 activate_.pending_replies.clear(); | |
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 matches are counted for the frame that is being removed, decrement the | |
210 // match total before erasing that entry. | |
211 auto it = matches_per_frame_.find(rfh); | |
212 if (it != matches_per_frame_.end()) { | |
213 number_of_matches_ -= it->second; | |
214 matches_per_frame_.erase(it); | |
215 } | |
216 | |
217 // Update the active match ordinal, since it may have changed. | |
218 if (active_frame_ == rfh) { | |
219 active_frame_ = nullptr; | |
220 relative_active_match_ordinal_ = 0; | |
221 } | |
222 UpdateActiveMatchOrdinal(); | |
223 | |
224 #if defined(OS_ANDROID) | |
225 // The removed frame may contain the nearest find result known so far. Note | |
226 // that once all queried frames have responded, if this result was the overall | |
227 // nearest, then no activation will occur. | |
228 if (rfh == activate_.nearest_frame) | |
229 activate_.nearest_frame = nullptr; | |
230 | |
231 // Match rects in the removed frame are no longer relevant. | |
232 if (match_rects_.count(rfh)) { | |
233 match_rects_.frame_rects.erase(rfh); | |
234 ++match_rects_.known_version; | |
235 } | |
236 | |
237 // A reply should not be expected from the removed frame. | |
238 RemoveNearestFindResultPendingReply(rfh); | |
239 RemoveFindMatchRectsPendingReply(rfh); | |
240 #endif | |
241 | |
242 if (pending_replies_.count(rfh)) { | |
243 // A reply should not be expected from the removed frame. | |
244 pending_replies_.erase(rfh); | |
245 if (pending_replies_.empty()) { | |
246 FinalUpdate(current_request_.id, rfh); | |
247 return; | |
248 } | |
249 } | |
250 | |
251 NotifyFindReply(current_session_id_, | |
252 pending_replies_.empty() /* final_update */); | |
74 } | 253 } |
75 | 254 |
76 #if defined(OS_ANDROID) | 255 #if defined(OS_ANDROID) |
77 void FindRequestManager::ActivateNearestFindResult(float x, | 256 void FindRequestManager::ActivateNearestFindResult(float x, float y) { |
78 float y) { | |
79 if (current_session_id_ == kInvalidId) | 257 if (current_session_id_ == kInvalidId) |
80 return; | 258 return; |
81 | 259 |
82 auto rfh = contents_->GetMainFrame(); | 260 activate_ = ActivateNearestFindResultState(x, y); |
83 rfh->Send(new InputMsg_ActivateNearestFindResult( | 261 |
84 rfh->GetRoutingID(), current_session_id_, x, y)); | 262 // Request from each frame the distance to the nearest find result (in that |
263 // frame) from the point (x, y), defined in find-in-page coordinates. | |
264 for (FrameTreeNode* node : contents_->GetFrameTree()->Nodes()) { | |
265 RenderFrameHost* rfh = node->current_frame_host(); | |
266 | |
267 if (!CheckFrame(rfh)) | |
268 continue; | |
269 | |
270 activate_.pending_replies.insert(rfh); | |
271 rfh->Send(new FrameMsg_GetNearestFindResult( | |
272 rfh->GetRoutingID(), activate_.current_request_id, | |
273 activate_.x, activate_.y)); | |
274 } | |
275 } | |
276 | |
277 void FindRequestManager::OnGetNearestFindResultReply(RenderFrameHost* rfh, | |
278 int request_id, | |
279 float distance) { | |
280 if (request_id != activate_.current_request_id || | |
281 !activate_.pending_replies.count(rfh)) { | |
282 return; | |
283 } | |
284 | |
285 // Check if this frame has a nearer find result than the current nearest. | |
286 if (distance < activate_.nearest_distance) { | |
287 activate_.nearest_frame = rfh; | |
288 activate_.nearest_distance = distance; | |
289 } | |
290 | |
291 RemoveNearestFindResultPendingReply(rfh); | |
85 } | 292 } |
86 | 293 |
87 void FindRequestManager::RequestFindMatchRects(int current_version) { | 294 void FindRequestManager::RequestFindMatchRects(int current_version) { |
295 match_rects_.pending_replies.clear(); | |
88 match_rects_.request_version = current_version; | 296 match_rects_.request_version = current_version; |
89 SendFindMatchRectsIPC(contents_->GetMainFrame()); | 297 |
298 // Request the latest find match rects from each frame. | |
299 for (FrameTreeNode* node : contents_->GetFrameTree()->Nodes()) { | |
300 RenderFrameHost* rfh = node->current_frame_host(); | |
301 | |
302 if (!CheckFrame(rfh)) | |
303 continue; | |
304 | |
305 match_rects_.pending_replies.insert(rfh); | |
306 auto it = match_rects_.frame_rects.find(rfh); | |
307 int version = (it != match_rects_.frame_rects.end()) | |
308 ? it->second.version : kInvalidId; | |
309 rfh->Send(new FrameMsg_FindMatchRects(rfh->GetRoutingID(), version)); | |
310 } | |
90 } | 311 } |
91 | 312 |
92 void FindRequestManager::OnFindMatchRectsReply( | 313 void FindRequestManager::OnFindMatchRectsReply( |
93 RenderFrameHost* rfh, | 314 RenderFrameHost* rfh, |
94 int version, | 315 int version, |
95 const std::vector<gfx::RectF>& rects, | 316 const std::vector<gfx::RectF>& rects, |
96 const gfx::RectF& active_rect) { | 317 const gfx::RectF& active_rect) { |
97 contents_->NotifyFindMatchRectsReply(version, rects, active_rect); | 318 auto it = match_rects_.frame_rects.find(rfh); |
319 if (it == match_rects_.frame_rects.end() || it->second.version != version) { | |
320 // New version of rects has been received, so update the data. | |
321 match_rects_.frame_rects[rfh] = FrameRects(rects, version); | |
322 ++match_rects_.known_version; | |
323 } | |
324 if (!active_rect.IsEmpty()) | |
325 match_rects_.active_rect = active_rect; | |
326 RemoveFindMatchRectsPendingReply(rfh); | |
98 } | 327 } |
99 #endif | 328 #endif |
100 | 329 |
330 void FindRequestManager::RenderFrameDeleted(RenderFrameHost* rfh) { | |
331 RemoveFrame(rfh); | |
332 } | |
333 | |
334 void FindRequestManager::RenderFrameHostChanged(RenderFrameHost* old_host, | |
335 RenderFrameHost* new_host) { | |
336 RemoveFrame(old_host); | |
337 } | |
338 | |
339 void FindRequestManager::FrameDeleted(RenderFrameHost* rfh) { | |
340 RemoveFrame(rfh); | |
341 } | |
342 | |
101 void FindRequestManager::Reset(const FindRequest& initial_request) { | 343 void FindRequestManager::Reset(const FindRequest& initial_request) { |
102 current_session_id_ = initial_request.id; | 344 current_session_id_ = initial_request.id; |
103 current_request_ = initial_request; | 345 current_request_ = initial_request; |
346 pending_replies_.clear(); | |
347 pending_active_match_ordinal_ = true; | |
348 matches_per_frame_.clear(); | |
104 number_of_matches_ = 0; | 349 number_of_matches_ = 0; |
350 active_frame_ = nullptr; | |
351 relative_active_match_ordinal_ = 0; | |
105 active_match_ordinal_ = 0; | 352 active_match_ordinal_ = 0; |
106 selection_rect_ = gfx::Rect(); | 353 selection_rect_ = gfx::Rect(); |
107 #if defined(OS_ANDROID) | 354 #if defined(OS_ANDROID) |
108 match_rects_ = FindMatchRectsState(); | 355 activate_ = ActivateNearestFindResultState(); |
356 match_rects_.pending_replies.clear(); | |
109 #endif | 357 #endif |
110 } | 358 } |
111 | 359 |
360 void FindRequestManager::FindInternal(const FindRequest& request) { | |
361 DCHECK_GT(request.id, current_request_.id); | |
362 DCHECK_GT(request.id, current_session_id_); | |
363 | |
364 if (request.options.findNext) { | |
365 // This is a find next operation. | |
366 | |
367 // This implies that there is an ongoing find session with the same search | |
368 // text. | |
369 DCHECK_GE(current_session_id_, 0); | |
370 DCHECK_EQ(request.search_text, current_request_.search_text); | |
371 | |
372 // The find next request will be directed at the focused frame if there is | |
373 // one, or the first frame with matches otherwise. | |
374 RenderFrameHost* target_rfh = contents_->GetFocusedFrame(); | |
375 if (!target_rfh || !CheckFrame(target_rfh)) | |
376 target_rfh = GetInitialFrame(request.options.forward); | |
377 | |
378 SendFindIPC(request, target_rfh); | |
379 current_request_ = request; | |
380 pending_active_match_ordinal_ = true; | |
381 return; | |
382 } | |
383 | |
384 // This is an initial find operation. | |
385 Reset(request); | |
386 for (FrameTreeNode* node : contents_->GetFrameTree()->Nodes()) | |
387 AddFrame(node->current_frame_host()); | |
388 } | |
389 | |
390 void FindRequestManager::AdvanceQueue(int request_id) { | |
391 if (find_request_queue_.empty() || | |
392 request_id != find_request_queue_.front().id) { | |
393 return; | |
394 } | |
395 | |
396 find_request_queue_.pop(); | |
397 if (!find_request_queue_.empty()) | |
398 FindInternal(find_request_queue_.front()); | |
399 } | |
400 | |
112 void FindRequestManager::SendFindIPC(const FindRequest& request, | 401 void FindRequestManager::SendFindIPC(const FindRequest& request, |
113 RenderFrameHost* rfh) { | 402 RenderFrameHost* rfh) { |
403 pending_replies_.insert(rfh); | |
114 rfh->Send(new FrameMsg_Find(rfh->GetRoutingID(), request.id, | 404 rfh->Send(new FrameMsg_Find(rfh->GetRoutingID(), request.id, |
115 request.search_text, request.options)); | 405 request.search_text, request.options)); |
116 } | 406 } |
117 | 407 |
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, | 408 void FindRequestManager::NotifyFindReply(int request_id, |
124 bool final_update) const { | 409 bool final_update) const { |
125 if (request_id == kInvalidId) { | 410 if (request_id == kInvalidId) { |
126 NOTREACHED(); | 411 NOTREACHED(); |
127 return; | 412 return; |
128 } | 413 } |
129 | 414 |
130 contents_->NotifyFindReply(request_id, number_of_matches_, selection_rect_, | 415 contents_->NotifyFindReply(request_id, number_of_matches_, selection_rect_, |
131 active_match_ordinal_, final_update); | 416 active_match_ordinal_, final_update); |
132 } | 417 } |
133 | 418 |
419 RenderFrameHost* FindRequestManager::GetInitialFrame(bool forward) const { | |
420 RenderFrameHost* rfh = contents_->GetMainFrame(); | |
421 | |
422 if (!forward) | |
423 rfh = GetDeepestLastChild(rfh); | |
424 | |
425 return rfh; | |
426 } | |
427 | |
428 RenderFrameHost* FindRequestManager::Traverse(RenderFrameHost* from_rfh, | |
429 bool forward, | |
430 bool matches_only, | |
431 bool wrap) const { | |
432 FrameTreeNode* node = | |
433 static_cast<RenderFrameHostImpl*>(from_rfh)->frame_tree_node(); | |
434 | |
435 while ((node = TraverseNode(node, forward, wrap)) != nullptr) { | |
436 if (!CheckFrame(node->current_frame_host())) | |
437 continue; | |
438 RenderFrameHost* current_rfh = node->current_frame_host(); | |
439 if (!matches_only || matches_per_frame_.find(current_rfh)->second || | |
440 pending_replies_.count(current_rfh)) { | |
441 // Note that if there is still a pending reply expected for this frame, | |
442 // then it may have unaccounted matches and will not be skipped via | |
443 // |matches_only|. | |
444 return node->current_frame_host(); | |
445 } | |
446 if (wrap && node->current_frame_host() == from_rfh) | |
447 return nullptr; | |
448 } | |
449 | |
450 return nullptr; | |
451 } | |
452 | |
453 void FindRequestManager::AddFrame(RenderFrameHost* rfh) { | |
454 if (!rfh || !rfh->IsRenderFrameLive()) | |
455 return; | |
456 | |
457 // A frame that is already being searched should not be added again. | |
458 DCHECK(!CheckFrame(rfh)); | |
459 | |
460 matches_per_frame_[rfh] = 0; | |
461 | |
462 FindRequest request = current_request_; | |
463 request.id = current_session_id_; | |
464 request.options.findNext = false; | |
465 SendFindIPC(request, rfh); | |
466 } | |
467 | |
468 bool FindRequestManager::CheckFrame(RenderFrameHost* rfh) const { | |
469 return rfh && rfh->IsRenderFrameLive() && matches_per_frame_.count(rfh); | |
470 } | |
471 | |
472 void FindRequestManager::UpdateActiveMatchOrdinal() { | |
473 active_match_ordinal_ = 0; | |
474 | |
475 if (!active_frame_ || !relative_active_match_ordinal_) { | |
476 DCHECK(!active_frame_ && !relative_active_match_ordinal_); | |
477 return; | |
478 } | |
479 | |
480 // Traverse the frame tree backwards (in search order) and count all of the | |
481 // matches in frames before the frame with the active match, in order to | |
482 // determine the overall active match ordinal. | |
483 RenderFrameHost* frame = active_frame_; | |
484 while ((frame = Traverse(frame, | |
485 false /* forward */, | |
486 true /* matches_only */, | |
487 false /* wrap */))) { | |
488 active_match_ordinal_ += matches_per_frame_[frame]; | |
489 } | |
490 active_match_ordinal_ += relative_active_match_ordinal_; | |
491 } | |
492 | |
493 void FindRequestManager::FinalUpdate(int request_id, RenderFrameHost* rfh) { | |
494 if (!number_of_matches_ || | |
495 !pending_active_match_ordinal_ || | |
496 request_id != current_request_.id) { | |
497 NotifyFindReply(request_id, true /* final_update */); | |
498 AdvanceQueue(request_id); | |
499 return; | |
500 } | |
501 | |
502 // There are matches, but no active match was returned, so another find next | |
503 // request must be sent. | |
504 | |
505 RenderFrameHost* target_rfh; | |
506 if (current_request_.options.findNext) { | |
507 // If this was a find next operation, then the active match will be in the | |
508 // next frame with matches after this one. | |
509 target_rfh = Traverse(rfh, | |
510 current_request_.options.forward, | |
511 true /* matches_only */, | |
512 true /* wrap */); | |
513 } else if ((target_rfh = contents_->GetFocusedFrame()) != nullptr) { | |
514 // Otherwise, if there is a focused frame, then the active match will be in | |
515 // the next frame with matches after that one. | |
516 target_rfh = Traverse(target_rfh, | |
517 current_request_.options.forward, | |
518 true /* matches_only */, | |
519 true /* wrap */); | |
520 } else { | |
521 // Otherwise, the first frame with matches will have the active match. | |
522 target_rfh = GetInitialFrame(current_request_.options.forward); | |
523 if (!CheckFrame(target_rfh) || !matches_per_frame_[target_rfh]) { | |
524 target_rfh = Traverse(target_rfh, | |
525 current_request_.options.forward, | |
526 true /* matches_only */, | |
527 false /* wrap */); | |
528 } | |
529 } | |
530 DCHECK(target_rfh); | |
531 | |
532 // Forward the find reply without |final_update| set because the active match | |
533 // has not yet been found. | |
534 NotifyFindReply(request_id, false /* final_update */); | |
535 | |
536 current_request_.options.findNext = true; | |
537 SendFindIPC(current_request_, target_rfh); | |
538 } | |
539 | |
134 #if defined(OS_ANDROID) | 540 #if defined(OS_ANDROID) |
135 void FindRequestManager::SendFindMatchRectsIPC(RenderFrameHost* rfh) { | 541 void FindRequestManager::RemoveNearestFindResultPendingReply( |
136 rfh->Send(new FrameMsg_FindMatchRects(rfh->GetRoutingID(), | 542 RenderFrameHost* rfh) { |
137 match_rects_.request_version)); | 543 auto it = activate_.pending_replies.find(rfh); |
544 if (it == activate_.pending_replies.end()) | |
545 return; | |
546 | |
547 activate_.pending_replies.erase(it); | |
548 if (activate_.pending_replies.empty() && | |
549 CheckFrame(activate_.nearest_frame)) { | |
550 activate_.nearest_frame->Send(new FrameMsg_ActivateNearestFindResult( | |
551 activate_.nearest_frame->GetRoutingID(), | |
552 current_session_id_, activate_.x, activate_.y)); | |
553 } | |
554 } | |
555 | |
556 void FindRequestManager::RemoveFindMatchRectsPendingReply( | |
557 RenderFrameHost* rfh) { | |
558 auto it = match_rects_.pending_replies.find(rfh); | |
559 if (it == match_rects_.pending_replies.end()) | |
560 return; | |
561 | |
562 match_rects_.pending_replies.erase(it); | |
563 if (match_rects_.pending_replies.empty()) { | |
564 // All replies are in. | |
565 std::vector<gfx::RectF> aggregate_rects; | |
566 if (match_rects_.request_version != match_rects_.known_version) { | |
567 // Request version is stale, so aggregate and report the newer find | |
568 // match rects. The rects should be aggregated in search order. | |
569 for (RenderFrameHost* frame = GetInitialFrame(true /* forward */); frame; | |
570 frame = Traverse(frame, | |
571 true /* forward */, | |
572 true /* matches_only */, | |
573 false /* wrap */)) { | |
574 auto it = match_rects_.frame_rects.find(frame); | |
575 if (it == match_rects_.frame_rects.end()) | |
576 continue; | |
577 | |
578 std::vector<gfx::RectF>& frame_rects = it->second.rects; | |
579 aggregate_rects.insert( | |
580 aggregate_rects.end(), frame_rects.begin(), frame_rects.end()); | |
581 } | |
582 } | |
583 contents_->NotifyFindMatchRectsReply( | |
584 match_rects_.known_version, aggregate_rects, match_rects_.active_rect); | |
585 } | |
138 } | 586 } |
139 #endif | 587 #endif |
140 | 588 |
141 } // namespace content | 589 } // namespace content |
OLD | NEW |