Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / extensions / browser / guest_view / web_view / web_view_find_helper.cc
blobd8e0b0bf6e0d0ddf40a8eac174e851f8dd40668b
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.
5 #include "extensions/browser/guest_view/web_view/web_view_find_helper.h"
7 #include <utility>
9 #include "components/guest_view/browser/guest_view_event.h"
10 #include "extensions/browser/api/guest_view/web_view/web_view_internal_api.h"
11 #include "extensions/browser/guest_view/web_view/web_view_constants.h"
13 using guest_view::GuestViewEvent;
15 namespace extensions {
17 WebViewFindHelper::WebViewFindHelper(WebViewGuest* webview_guest)
18 : webview_guest_(webview_guest), current_find_request_id_(0) {
21 WebViewFindHelper::~WebViewFindHelper() {
24 void WebViewFindHelper::CancelAllFindSessions() {
25 current_find_session_ = linked_ptr<WebViewFindHelper::FindInfo>();
26 while (!find_info_map_.empty()) {
27 find_info_map_.begin()->second->SendResponse(true /* canceled */);
28 find_info_map_.erase(find_info_map_.begin());
30 if (find_update_event_.get())
31 DispatchFindUpdateEvent(true /* canceled */, true /* final_update */);
32 find_update_event_.reset();
35 void WebViewFindHelper::DispatchFindUpdateEvent(bool canceled,
36 bool final_update) {
37 DCHECK(find_update_event_.get());
38 scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue());
39 find_update_event_->PrepareResults(args.get());
40 args->SetBoolean(webview::kFindCanceled, canceled);
41 args->SetBoolean(webview::kFindFinalUpdate, final_update);
42 DCHECK(webview_guest_);
43 webview_guest_->DispatchEventToView(
44 new GuestViewEvent(webview::kEventFindReply, args.Pass()));
47 void WebViewFindHelper::EndFindSession(int session_request_id, bool canceled) {
48 FindInfoMap::iterator session_iterator =
49 find_info_map_.find(session_request_id);
50 DCHECK(session_iterator != find_info_map_.end());
51 FindInfo* find_info = session_iterator->second.get();
53 // Call the callback function of the first request of the find session.
54 find_info->SendResponse(canceled);
56 // For every subsequent find request of the find session.
57 for (std::vector<base::WeakPtr<WebViewFindHelper::FindInfo> >::iterator i =
58 find_info->find_next_requests_.begin();
59 i != find_info->find_next_requests_.end();
60 ++i) {
61 DCHECK(i->get());
63 // Do not call callbacks for subsequent find requests that have not been
64 // replied to yet. These requests will get their own final updates in the
65 // same order as they appear in |find_next_requests_|, i.e. the order that
66 // the requests were made in. Once one request is found that has not been
67 // replied to, none that follow will be replied to either, and do not need
68 // to be checked.
69 if (!(*i)->replied_)
70 break;
72 // Update the request's number of matches (if not canceled).
73 if (!canceled) {
74 (*i)->find_results_.number_of_matches_ =
75 find_info->find_results_.number_of_matches_;
78 // Call the request's callback function with the find results, and then
79 // delete its map entry to free the WebViewInternalFindFunction object.
80 (*i)->SendResponse(canceled);
81 find_info_map_.erase((*i)->request_id_);
84 // Erase the first find request's map entry to free the
85 // WebViewInternalFindFunction
86 // object.
87 find_info_map_.erase(session_request_id);
90 void WebViewFindHelper::Find(
91 content::WebContents* guest_web_contents,
92 const base::string16& search_text,
93 const blink::WebFindOptions& options,
94 scoped_refptr<WebViewInternalFindFunction> find_function) {
95 // Need a new request_id for each new find request.
96 ++current_find_request_id_;
98 // Stores the find request information by request_id so that its callback
99 // function can be called when the find results are available.
100 std::pair<FindInfoMap::iterator, bool> insert_result =
101 find_info_map_.insert(std::make_pair(
102 current_find_request_id_,
103 linked_ptr<
104 WebViewFindHelper::FindInfo>(new WebViewFindHelper::FindInfo(
105 current_find_request_id_, search_text, options, find_function))));
106 // No duplicate insertions.
107 DCHECK(insert_result.second);
109 // Find options including the implicit |findNext| field.
110 blink::WebFindOptions* full_options = insert_result.first->second->options();
112 // Set |findNext| implicitly.
113 if (current_find_session_.get()) {
114 const base::string16& current_search_text =
115 current_find_session_->search_text();
116 bool current_match_case = current_find_session_->options()->matchCase;
117 full_options->findNext = !current_search_text.empty() &&
118 current_search_text == search_text &&
119 current_match_case == options.matchCase;
120 } else {
121 full_options->findNext = false;
124 // Link find requests that are a part of the same find session.
125 if (full_options->findNext && current_find_session_.get()) {
126 DCHECK(current_find_request_id_ != current_find_session_->request_id());
127 current_find_session_->AddFindNextRequest(
128 insert_result.first->second->AsWeakPtr());
131 // Update the current find session, if necessary.
132 if (!full_options->findNext)
133 current_find_session_ = insert_result.first->second;
135 guest_web_contents->Find(current_find_request_id_,
136 search_text, *full_options);
139 void WebViewFindHelper::FindReply(int request_id,
140 int number_of_matches,
141 const gfx::Rect& selection_rect,
142 int active_match_ordinal,
143 bool final_update) {
144 FindInfoMap::iterator find_iterator = find_info_map_.find(request_id);
146 // Ignore slow replies to canceled find requests.
147 if (find_iterator == find_info_map_.end())
148 return;
150 // This find request must be a part of an existing find session.
151 DCHECK(current_find_session_.get());
153 WebViewFindHelper::FindInfo* find_info = find_iterator->second.get();
155 // Handle canceled find requests.
156 if (!find_info->options()->findNext &&
157 find_info_map_.begin()->first < request_id) {
158 DCHECK_NE(current_find_session_->request_id(),
159 find_info_map_.begin()->first);
160 DispatchFindUpdateEvent(true /* canceled */, true /* final_update */);
161 EndFindSession(find_info_map_.begin()->first, true /* canceled */);
164 // Clears the results for |findupdate| for a new find session.
165 if (!find_info->replied() && !find_info->options()->findNext)
166 find_update_event_.reset(new FindUpdateEvent(find_info->search_text()));
168 // Aggregate the find results.
169 find_info->AggregateResults(number_of_matches, selection_rect,
170 active_match_ordinal, final_update);
171 find_update_event_->AggregateResults(number_of_matches, selection_rect,
172 active_match_ordinal, final_update);
174 // Propagate incremental results to the |findupdate| event.
175 DispatchFindUpdateEvent(false /* canceled */, final_update);
177 // Call the callback functions of completed find requests.
178 if (final_update)
179 EndFindSession(request_id, false /* canceled */);
182 WebViewFindHelper::FindResults::FindResults()
183 : number_of_matches_(0), active_match_ordinal_(0) {
186 WebViewFindHelper::FindResults::~FindResults() {
189 void WebViewFindHelper::FindResults::AggregateResults(
190 int number_of_matches,
191 const gfx::Rect& selection_rect,
192 int active_match_ordinal,
193 bool final_update) {
194 if (number_of_matches != -1)
195 number_of_matches_ = number_of_matches;
197 if (active_match_ordinal != -1)
198 active_match_ordinal_ = active_match_ordinal;
200 if (final_update && active_match_ordinal_ == 0) {
201 // No match found, so the selection rectangle is empty.
202 selection_rect_ = gfx::Rect();
203 } else if (!selection_rect.IsEmpty()) {
204 selection_rect_ = selection_rect;
208 void WebViewFindHelper::FindResults::PrepareResults(
209 base::DictionaryValue* results) {
210 results->SetInteger(webview::kFindNumberOfMatches, number_of_matches_);
211 results->SetInteger(webview::kFindActiveMatchOrdinal, active_match_ordinal_);
212 base::DictionaryValue rect;
213 rect.SetInteger(webview::kFindRectLeft, selection_rect_.x());
214 rect.SetInteger(webview::kFindRectTop, selection_rect_.y());
215 rect.SetInteger(webview::kFindRectWidth, selection_rect_.width());
216 rect.SetInteger(webview::kFindRectHeight, selection_rect_.height());
217 results->Set(webview::kFindSelectionRect, rect.DeepCopy());
220 WebViewFindHelper::FindUpdateEvent::FindUpdateEvent(
221 const base::string16& search_text)
222 : search_text_(search_text) {
225 WebViewFindHelper::FindUpdateEvent::~FindUpdateEvent() {
228 void WebViewFindHelper::FindUpdateEvent::AggregateResults(
229 int number_of_matches,
230 const gfx::Rect& selection_rect,
231 int active_match_ordinal,
232 bool final_update) {
233 find_results_.AggregateResults(number_of_matches, selection_rect,
234 active_match_ordinal, final_update);
237 void WebViewFindHelper::FindUpdateEvent::PrepareResults(
238 base::DictionaryValue* results) {
239 results->SetString(webview::kFindSearchText, search_text_);
240 find_results_.PrepareResults(results);
243 WebViewFindHelper::FindInfo::FindInfo(
244 int request_id,
245 const base::string16& search_text,
246 const blink::WebFindOptions& options,
247 scoped_refptr<WebViewInternalFindFunction> find_function)
248 : request_id_(request_id),
249 search_text_(search_text),
250 options_(options),
251 find_function_(find_function),
252 replied_(false),
253 weak_ptr_factory_(this) {
256 WebViewFindHelper::FindInfo::~FindInfo() {
259 void WebViewFindHelper::FindInfo::AggregateResults(
260 int number_of_matches,
261 const gfx::Rect& selection_rect,
262 int active_match_ordinal,
263 bool final_update) {
264 replied_ = true;
265 find_results_.AggregateResults(number_of_matches, selection_rect,
266 active_match_ordinal, final_update);
269 base::WeakPtr<WebViewFindHelper::FindInfo>
270 WebViewFindHelper::FindInfo::AsWeakPtr() {
271 return weak_ptr_factory_.GetWeakPtr();
274 void WebViewFindHelper::FindInfo::SendResponse(bool canceled) {
275 // Prepare the find results to pass to the callback function.
276 base::DictionaryValue results;
277 find_results_.PrepareResults(&results);
278 results.SetBoolean(webview::kFindCanceled, canceled);
280 // Call the callback.
281 find_function_->SetResult(results.DeepCopy());
282 find_function_->SendResponse(true);
285 } // namespace extensions