Chromium Code Reviews| 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 |