| OLD | NEW |
| (Empty) |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "chrome/browser/guest_view/web_view/web_view_find_helper.h" | |
| 6 | |
| 7 #include <utility> | |
| 8 | |
| 9 #include "chrome/browser/extensions/api/webview/webview_api.h" | |
| 10 #include "chrome/browser/guest_view/web_view/web_view_constants.h" | |
| 11 | |
| 12 WebviewFindHelper::WebviewFindHelper(WebViewGuest* webview_guest) | |
| 13 : webview_guest_(webview_guest), | |
| 14 current_find_request_id_(0) { | |
| 15 } | |
| 16 | |
| 17 WebviewFindHelper::~WebviewFindHelper() { | |
| 18 } | |
| 19 | |
| 20 void WebviewFindHelper::CancelAllFindSessions() { | |
| 21 current_find_session_ = linked_ptr<WebviewFindHelper::FindInfo>(); | |
| 22 while (!find_info_map_.empty()) { | |
| 23 find_info_map_.begin()->second->SendResponse(true /* canceled */); | |
| 24 find_info_map_.erase(find_info_map_.begin()); | |
| 25 } | |
| 26 if (find_update_event_.get()) | |
| 27 DispatchFindUpdateEvent(true /* canceled */, true /* final_update */); | |
| 28 find_update_event_.reset(); | |
| 29 } | |
| 30 | |
| 31 void WebviewFindHelper::DispatchFindUpdateEvent(bool canceled, | |
| 32 bool final_update) { | |
| 33 DCHECK(find_update_event_.get()); | |
| 34 scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); | |
| 35 find_update_event_->PrepareResults(args.get()); | |
| 36 args->SetBoolean(webview::kFindCanceled, canceled); | |
| 37 args->SetBoolean(webview::kFindFinalUpdate, final_update); | |
| 38 DCHECK(webview_guest_); | |
| 39 webview_guest_->DispatchEvent( | |
| 40 new GuestViewBase::Event(webview::kEventFindReply, args.Pass())); | |
| 41 } | |
| 42 | |
| 43 void WebviewFindHelper::EndFindSession(int session_request_id, bool canceled) { | |
| 44 FindInfoMap::iterator session_iterator = | |
| 45 find_info_map_.find(session_request_id); | |
| 46 DCHECK(session_iterator != find_info_map_.end()); | |
| 47 FindInfo* find_info = session_iterator->second.get(); | |
| 48 | |
| 49 // Call the callback function of the first request of the find session. | |
| 50 find_info->SendResponse(canceled); | |
| 51 | |
| 52 // For every subsequent find request of the find session. | |
| 53 for (std::vector<base::WeakPtr<WebviewFindHelper::FindInfo> >::iterator i = | |
| 54 find_info->find_next_requests_.begin(); | |
| 55 i != find_info->find_next_requests_.end(); ++i) { | |
| 56 DCHECK(i->get()); | |
| 57 | |
| 58 // Do not call callbacks for subsequent find requests that have not been | |
| 59 // replied to yet. These requests will get their own final updates in the | |
| 60 // same order as they appear in |find_next_requests_|, i.e. the order that | |
| 61 // the requests were made in. Once one request is found that has not been | |
| 62 // replied to, none that follow will be replied to either, and do not need | |
| 63 // to be checked. | |
| 64 if (!(*i)->replied_) | |
| 65 break; | |
| 66 | |
| 67 // Update the request's number of matches (if not canceled). | |
| 68 if (!canceled) { | |
| 69 (*i)->find_results_.number_of_matches_ = | |
| 70 find_info->find_results_.number_of_matches_; | |
| 71 } | |
| 72 | |
| 73 // Call the request's callback function with the find results, and then | |
| 74 // delete its map entry to free the WebviewFindFunction object. | |
| 75 (*i)->SendResponse(canceled); | |
| 76 find_info_map_.erase((*i)->request_id_); | |
| 77 } | |
| 78 | |
| 79 // Erase the first find request's map entry to free the WebviewFindFunction | |
| 80 // object. | |
| 81 find_info_map_.erase(session_request_id); | |
| 82 } | |
| 83 | |
| 84 void WebviewFindHelper::Find( | |
| 85 content::WebContents* guest_web_contents, | |
| 86 const base::string16& search_text, | |
| 87 const blink::WebFindOptions& options, | |
| 88 scoped_refptr<extensions::WebviewFindFunction> find_function) { | |
| 89 // Need a new request_id for each new find request. | |
| 90 ++current_find_request_id_; | |
| 91 | |
| 92 // Stores the find request information by request_id so that its callback | |
| 93 // function can be called when the find results are available. | |
| 94 std::pair<FindInfoMap::iterator, bool> insert_result = | |
| 95 find_info_map_.insert( | |
| 96 std::make_pair(current_find_request_id_, | |
| 97 linked_ptr<WebviewFindHelper::FindInfo>( | |
| 98 new WebviewFindHelper::FindInfo( | |
| 99 current_find_request_id_, | |
| 100 search_text, | |
| 101 options, | |
| 102 find_function)))); | |
| 103 // No duplicate insertions. | |
| 104 DCHECK(insert_result.second); | |
| 105 | |
| 106 // Find options including the implicit |findNext| field. | |
| 107 blink::WebFindOptions* full_options = insert_result.first->second->options(); | |
| 108 | |
| 109 // Set |findNext| implicitly. | |
| 110 if (current_find_session_.get()) { | |
| 111 const base::string16& current_search_text = | |
| 112 current_find_session_->search_text(); | |
| 113 bool current_match_case = current_find_session_->options()->matchCase; | |
| 114 full_options->findNext = !current_search_text.empty() && | |
| 115 current_search_text == search_text && | |
| 116 current_match_case == options.matchCase; | |
| 117 } else { | |
| 118 full_options->findNext = false; | |
| 119 } | |
| 120 | |
| 121 // Link find requests that are a part of the same find session. | |
| 122 if (full_options->findNext && current_find_session_.get()) { | |
| 123 DCHECK(current_find_request_id_ != current_find_session_->request_id()); | |
| 124 current_find_session_->AddFindNextRequest( | |
| 125 insert_result.first->second->AsWeakPtr()); | |
| 126 } | |
| 127 | |
| 128 // Update the current find session, if necessary. | |
| 129 if (!full_options->findNext) | |
| 130 current_find_session_ = insert_result.first->second; | |
| 131 | |
| 132 guest_web_contents->Find(current_find_request_id_, | |
| 133 search_text, *full_options); | |
| 134 } | |
| 135 | |
| 136 void WebviewFindHelper::FindReply(int request_id, | |
| 137 int number_of_matches, | |
| 138 const gfx::Rect& selection_rect, | |
| 139 int active_match_ordinal, | |
| 140 bool final_update) { | |
| 141 FindInfoMap::iterator find_iterator = find_info_map_.find(request_id); | |
| 142 | |
| 143 // Ignore slow replies to canceled find requests. | |
| 144 if (find_iterator == find_info_map_.end()) | |
| 145 return; | |
| 146 | |
| 147 // This find request must be a part of an existing find session. | |
| 148 DCHECK(current_find_session_.get()); | |
| 149 | |
| 150 WebviewFindHelper::FindInfo* find_info = find_iterator->second.get(); | |
| 151 | |
| 152 // Handle canceled find requests. | |
| 153 if (!find_info->options()->findNext && | |
| 154 find_info_map_.begin()->first < request_id) { | |
| 155 DCHECK_NE(current_find_session_->request_id(), | |
| 156 find_info_map_.begin()->first); | |
| 157 DispatchFindUpdateEvent(true /* canceled */, true /* final_update */); | |
| 158 EndFindSession(find_info_map_.begin()->first, true /* canceled */); | |
| 159 } | |
| 160 | |
| 161 // Clears the results for |findupdate| for a new find session. | |
| 162 if (!find_info->replied() && !find_info->options()->findNext) | |
| 163 find_update_event_.reset(new FindUpdateEvent(find_info->search_text())); | |
| 164 | |
| 165 // Aggregate the find results. | |
| 166 find_info->AggregateResults(number_of_matches, selection_rect, | |
| 167 active_match_ordinal, final_update); | |
| 168 find_update_event_->AggregateResults(number_of_matches, selection_rect, | |
| 169 active_match_ordinal, final_update); | |
| 170 | |
| 171 // Propagate incremental results to the |findupdate| event. | |
| 172 DispatchFindUpdateEvent(false /* canceled */, final_update); | |
| 173 | |
| 174 // Call the callback functions of completed find requests. | |
| 175 if (final_update) | |
| 176 EndFindSession(request_id, false /* canceled */); | |
| 177 } | |
| 178 | |
| 179 WebviewFindHelper::FindResults::FindResults() | |
| 180 : number_of_matches_(0), | |
| 181 active_match_ordinal_(0) {} | |
| 182 | |
| 183 WebviewFindHelper::FindResults::~FindResults() { | |
| 184 } | |
| 185 | |
| 186 void WebviewFindHelper::FindResults::AggregateResults( | |
| 187 int number_of_matches, | |
| 188 const gfx::Rect& selection_rect, | |
| 189 int active_match_ordinal, | |
| 190 bool final_update) { | |
| 191 if (number_of_matches != -1) | |
| 192 number_of_matches_ = number_of_matches; | |
| 193 | |
| 194 if (active_match_ordinal != -1) | |
| 195 active_match_ordinal_ = active_match_ordinal; | |
| 196 | |
| 197 if (final_update && active_match_ordinal_ == 0) { | |
| 198 // No match found, so the selection rectangle is empty. | |
| 199 selection_rect_ = gfx::Rect(); | |
| 200 } else if (!selection_rect.IsEmpty()) { | |
| 201 selection_rect_ = selection_rect; | |
| 202 } | |
| 203 } | |
| 204 | |
| 205 void WebviewFindHelper::FindResults::PrepareResults( | |
| 206 base::DictionaryValue* results) { | |
| 207 results->SetInteger(webview::kFindNumberOfMatches, number_of_matches_); | |
| 208 results->SetInteger(webview::kFindActiveMatchOrdinal, active_match_ordinal_); | |
| 209 base::DictionaryValue rect; | |
| 210 rect.SetInteger(webview::kFindRectLeft, selection_rect_.x()); | |
| 211 rect.SetInteger(webview::kFindRectTop, selection_rect_.y()); | |
| 212 rect.SetInteger(webview::kFindRectWidth, selection_rect_.width()); | |
| 213 rect.SetInteger(webview::kFindRectHeight, selection_rect_.height()); | |
| 214 results->Set(webview::kFindSelectionRect, rect.DeepCopy()); | |
| 215 } | |
| 216 | |
| 217 WebviewFindHelper::FindUpdateEvent::FindUpdateEvent( | |
| 218 const base::string16& search_text) : search_text_(search_text) { | |
| 219 } | |
| 220 | |
| 221 WebviewFindHelper::FindUpdateEvent::~FindUpdateEvent() { | |
| 222 } | |
| 223 | |
| 224 void WebviewFindHelper::FindUpdateEvent::AggregateResults( | |
| 225 int number_of_matches, | |
| 226 const gfx::Rect& selection_rect, | |
| 227 int active_match_ordinal, | |
| 228 bool final_update) { | |
| 229 find_results_.AggregateResults(number_of_matches, selection_rect, | |
| 230 active_match_ordinal, final_update); | |
| 231 } | |
| 232 | |
| 233 void WebviewFindHelper::FindUpdateEvent::PrepareResults( | |
| 234 base::DictionaryValue* results) { | |
| 235 results->SetString(webview::kFindSearchText, search_text_); | |
| 236 find_results_.PrepareResults(results); | |
| 237 } | |
| 238 | |
| 239 WebviewFindHelper::FindInfo::FindInfo( | |
| 240 int request_id, | |
| 241 const base::string16& search_text, | |
| 242 const blink::WebFindOptions& options, | |
| 243 scoped_refptr<extensions::WebviewFindFunction> find_function) | |
| 244 : request_id_(request_id), | |
| 245 search_text_(search_text), | |
| 246 options_(options), | |
| 247 find_function_(find_function), | |
| 248 replied_(false), | |
| 249 weak_ptr_factory_(this) { | |
| 250 } | |
| 251 | |
| 252 WebviewFindHelper::FindInfo::~FindInfo() { | |
| 253 } | |
| 254 | |
| 255 void WebviewFindHelper::FindInfo::AggregateResults( | |
| 256 int number_of_matches, | |
| 257 const gfx::Rect& selection_rect, | |
| 258 int active_match_ordinal, | |
| 259 bool final_update) { | |
| 260 replied_ = true; | |
| 261 find_results_.AggregateResults(number_of_matches, selection_rect, | |
| 262 active_match_ordinal, final_update); | |
| 263 } | |
| 264 | |
| 265 base::WeakPtr<WebviewFindHelper::FindInfo> | |
| 266 WebviewFindHelper::FindInfo::AsWeakPtr() { | |
| 267 return weak_ptr_factory_.GetWeakPtr(); | |
| 268 } | |
| 269 | |
| 270 void WebviewFindHelper::FindInfo::SendResponse(bool canceled) { | |
| 271 // Prepare the find results to pass to the callback function. | |
| 272 base::DictionaryValue results; | |
| 273 find_results_.PrepareResults(&results); | |
| 274 results.SetBoolean(webview::kFindCanceled, canceled); | |
| 275 | |
| 276 // Call the callback. | |
| 277 find_function_->SetResult(results.DeepCopy()); | |
| 278 find_function_->SendResponse(true); | |
| 279 } | |
| OLD | NEW |