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 "extensions/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 "extensions/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 |