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/web_view/web_view_internal_api.h" |
| 10 #include "chrome/browser/guest_view/web_view/web_view_constants.h" |
| 11 |
| 12 namespace extensions { |
| 13 |
| 14 WebViewFindHelper::WebViewFindHelper(WebViewGuest* webview_guest) |
| 15 : webview_guest_(webview_guest), current_find_request_id_(0) { |
| 16 } |
| 17 |
| 18 WebViewFindHelper::~WebViewFindHelper() { |
| 19 } |
| 20 |
| 21 void WebViewFindHelper::CancelAllFindSessions() { |
| 22 current_find_session_ = linked_ptr<WebViewFindHelper::FindInfo>(); |
| 23 while (!find_info_map_.empty()) { |
| 24 find_info_map_.begin()->second->SendResponse(true /* canceled */); |
| 25 find_info_map_.erase(find_info_map_.begin()); |
| 26 } |
| 27 if (find_update_event_.get()) |
| 28 DispatchFindUpdateEvent(true /* canceled */, true /* final_update */); |
| 29 find_update_event_.reset(); |
| 30 } |
| 31 |
| 32 void WebViewFindHelper::DispatchFindUpdateEvent(bool canceled, |
| 33 bool final_update) { |
| 34 DCHECK(find_update_event_.get()); |
| 35 scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); |
| 36 find_update_event_->PrepareResults(args.get()); |
| 37 args->SetBoolean(webview::kFindCanceled, canceled); |
| 38 args->SetBoolean(webview::kFindFinalUpdate, final_update); |
| 39 DCHECK(webview_guest_); |
| 40 webview_guest_->DispatchEventToEmbedder( |
| 41 new GuestViewBase::Event(webview::kEventFindReply, args.Pass())); |
| 42 } |
| 43 |
| 44 void WebViewFindHelper::EndFindSession(int session_request_id, bool canceled) { |
| 45 FindInfoMap::iterator session_iterator = |
| 46 find_info_map_.find(session_request_id); |
| 47 DCHECK(session_iterator != find_info_map_.end()); |
| 48 FindInfo* find_info = session_iterator->second.get(); |
| 49 |
| 50 // Call the callback function of the first request of the find session. |
| 51 find_info->SendResponse(canceled); |
| 52 |
| 53 // For every subsequent find request of the find session. |
| 54 for (std::vector<base::WeakPtr<WebViewFindHelper::FindInfo> >::iterator i = |
| 55 find_info->find_next_requests_.begin(); |
| 56 i != find_info->find_next_requests_.end(); |
| 57 ++i) { |
| 58 DCHECK(i->get()); |
| 59 |
| 60 // Do not call callbacks for subsequent find requests that have not been |
| 61 // replied to yet. These requests will get their own final updates in the |
| 62 // same order as they appear in |find_next_requests_|, i.e. the order that |
| 63 // the requests were made in. Once one request is found that has not been |
| 64 // replied to, none that follow will be replied to either, and do not need |
| 65 // to be checked. |
| 66 if (!(*i)->replied_) |
| 67 break; |
| 68 |
| 69 // Update the request's number of matches (if not canceled). |
| 70 if (!canceled) { |
| 71 (*i)->find_results_.number_of_matches_ = |
| 72 find_info->find_results_.number_of_matches_; |
| 73 } |
| 74 |
| 75 // Call the request's callback function with the find results, and then |
| 76 // delete its map entry to free the WebViewInternalFindFunction object. |
| 77 (*i)->SendResponse(canceled); |
| 78 find_info_map_.erase((*i)->request_id_); |
| 79 } |
| 80 |
| 81 // Erase the first find request's map entry to free the |
| 82 // WebViewInternalFindFunction |
| 83 // object. |
| 84 find_info_map_.erase(session_request_id); |
| 85 } |
| 86 |
| 87 void WebViewFindHelper::Find( |
| 88 content::WebContents* guest_web_contents, |
| 89 const base::string16& search_text, |
| 90 const blink::WebFindOptions& options, |
| 91 scoped_refptr<WebViewInternalFindFunction> find_function) { |
| 92 // Need a new request_id for each new find request. |
| 93 ++current_find_request_id_; |
| 94 |
| 95 // Stores the find request information by request_id so that its callback |
| 96 // function can be called when the find results are available. |
| 97 std::pair<FindInfoMap::iterator, bool> insert_result = |
| 98 find_info_map_.insert(std::make_pair( |
| 99 current_find_request_id_, |
| 100 linked_ptr< |
| 101 WebViewFindHelper::FindInfo>(new WebViewFindHelper::FindInfo( |
| 102 current_find_request_id_, search_text, options, 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), active_match_ordinal_(0) { |
| 181 } |
| 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) |
| 219 : search_text_(search_text) { |
| 220 } |
| 221 |
| 222 WebViewFindHelper::FindUpdateEvent::~FindUpdateEvent() { |
| 223 } |
| 224 |
| 225 void WebViewFindHelper::FindUpdateEvent::AggregateResults( |
| 226 int number_of_matches, |
| 227 const gfx::Rect& selection_rect, |
| 228 int active_match_ordinal, |
| 229 bool final_update) { |
| 230 find_results_.AggregateResults(number_of_matches, selection_rect, |
| 231 active_match_ordinal, final_update); |
| 232 } |
| 233 |
| 234 void WebViewFindHelper::FindUpdateEvent::PrepareResults( |
| 235 base::DictionaryValue* results) { |
| 236 results->SetString(webview::kFindSearchText, search_text_); |
| 237 find_results_.PrepareResults(results); |
| 238 } |
| 239 |
| 240 WebViewFindHelper::FindInfo::FindInfo( |
| 241 int request_id, |
| 242 const base::string16& search_text, |
| 243 const blink::WebFindOptions& options, |
| 244 scoped_refptr<WebViewInternalFindFunction> find_function) |
| 245 : request_id_(request_id), |
| 246 search_text_(search_text), |
| 247 options_(options), |
| 248 find_function_(find_function), |
| 249 replied_(false), |
| 250 weak_ptr_factory_(this) { |
| 251 } |
| 252 |
| 253 WebViewFindHelper::FindInfo::~FindInfo() { |
| 254 } |
| 255 |
| 256 void WebViewFindHelper::FindInfo::AggregateResults( |
| 257 int number_of_matches, |
| 258 const gfx::Rect& selection_rect, |
| 259 int active_match_ordinal, |
| 260 bool final_update) { |
| 261 replied_ = true; |
| 262 find_results_.AggregateResults(number_of_matches, selection_rect, |
| 263 active_match_ordinal, final_update); |
| 264 } |
| 265 |
| 266 base::WeakPtr<WebViewFindHelper::FindInfo> |
| 267 WebViewFindHelper::FindInfo::AsWeakPtr() { |
| 268 return weak_ptr_factory_.GetWeakPtr(); |
| 269 } |
| 270 |
| 271 void WebViewFindHelper::FindInfo::SendResponse(bool canceled) { |
| 272 // Prepare the find results to pass to the callback function. |
| 273 base::DictionaryValue results; |
| 274 find_results_.PrepareResults(&results); |
| 275 results.SetBoolean(webview::kFindCanceled, canceled); |
| 276 |
| 277 // Call the callback. |
| 278 find_function_->SetResult(results.DeepCopy()); |
| 279 find_function_->SendResponse(true); |
| 280 } |
| 281 |
| 282 } // namespace extensions |
OLD | NEW |