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 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 |
OLD | NEW |