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 |