OLD | NEW |
---|---|
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/android/contextualsearch/contextual_search_delegate.h" | 5 #include "chrome/browser/android/contextualsearch/contextual_search_delegate.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <utility> | 8 #include <utility> |
9 | 9 |
10 #include "base/base64.h" | 10 #include "base/base64.h" |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
91 template_url_service_(template_url_service), | 91 template_url_service_(template_url_service), |
92 search_term_callback_(search_term_callback), | 92 search_term_callback_(search_term_callback), |
93 surrounding_callback_(surrounding_callback), | 93 surrounding_callback_(surrounding_callback), |
94 icing_callback_(icing_callback) { | 94 icing_callback_(icing_callback) { |
95 field_trial_.reset(new ContextualSearchFieldTrial()); | 95 field_trial_.reset(new ContextualSearchFieldTrial()); |
96 } | 96 } |
97 | 97 |
98 ContextualSearchDelegate::~ContextualSearchDelegate() { | 98 ContextualSearchDelegate::~ContextualSearchDelegate() { |
99 } | 99 } |
100 | 100 |
101 void ContextualSearchDelegate::StartSearchTermResolutionRequest( | 101 void ContextualSearchDelegate::GatherAndSaveSurroundingText( |
102 const std::string& selection, | 102 ContextualSearchContext* contextual_search_context, |
103 const std::string& home_country, | 103 content::WebContents* web_contents) { |
104 content::WebContents* web_contents, | 104 DCHECK(web_contents); |
105 bool may_send_base_page_url) { | 105 RenderFrameHost::TextSurroundingSelectionCallback callback = |
106 GatherSurroundingTextWithCallback( | 106 base::Bind(&ContextualSearchDelegate::OnTextSurroundingSelectionAvailable, |
107 selection, home_country, web_contents, may_send_base_page_url, | 107 AsWeakPtr()); |
108 base::Bind(&ContextualSearchDelegate::StartSearchTermRequestFromSelection, | 108 context_ = contextual_search_context; |
109 AsWeakPtr())); | 109 int surroundingTextSize = context_->IsBrief() |
110 ? field_trial_->GetIcingSurroundingSize() | |
111 : field_trial_->GetSurroundingSize(); | |
112 RenderFrameHost* focused_frame = web_contents->GetFocusedFrame(); | |
113 if (focused_frame) { | |
114 focused_frame->RequestTextSurroundingSelection(callback, | |
115 surroundingTextSize); | |
116 } else { | |
117 callback.Run(base::string16(), 0, 0); | |
118 } | |
110 } | 119 } |
111 | 120 |
112 void ContextualSearchDelegate::GatherAndSaveSurroundingText( | 121 void ContextualSearchDelegate::StartSearchTermResolutionRequest( |
Theresa
2017/03/08 01:54:38
nit: It looks like this method and the one above g
Donn Denman
2017/03/09 17:35:05
Fixed -- Changed the order in the header file to b
| |
113 const std::string& selection, | 122 ContextualSearchContext* contextual_search_context, |
114 const std::string& home_country, | 123 content::WebContents* web_contents) { |
115 content::WebContents* web_contents, | 124 DCHECK(web_contents); |
116 bool may_send_base_page_url) { | 125 DCHECK(context_ == contextual_search_context); |
117 GatherSurroundingTextWithCallback( | 126 DCHECK(!context_->IsBrief()); |
118 selection, home_country, web_contents, may_send_base_page_url, | 127 |
119 base::Bind(&ContextualSearchDelegate::SaveSurroundingText, AsWeakPtr())); | 128 // Immediately cancel any request that's in flight, since we're building a new |
120 // TODO(donnd): clear the context here, since we're done with it (but risky). | 129 // context (and the response disposes of any existing context). |
130 search_term_fetcher_.reset(); | |
131 | |
132 // Decide if the URL should be sent with the context. | |
133 GURL page_url(web_contents->GetURL()); | |
134 GURL url_to_send; | |
135 if (context_->MaySendBasePageUrl() && | |
136 CanSendPageURL(page_url, ProfileManager::GetActiveUserProfile(), | |
137 template_url_service_)) { | |
138 url_to_send = page_url; | |
139 } | |
140 std::string encoding(web_contents->GetEncoding()); | |
141 context_->page_url = url_to_send; | |
142 context_->encoding = encoding; | |
143 ResolveSearchTermFromContext(); | |
121 } | 144 } |
122 | 145 |
123 void ContextualSearchDelegate::ContinueSearchTermResolutionRequest() { | 146 void ContextualSearchDelegate::ResolveSearchTermFromContext() { |
124 DCHECK(context_.get()); | 147 DCHECK(context_); |
125 if (!context_.get()) | 148 if (!context_) |
126 return; | 149 return; |
127 GURL request_url(BuildRequestUrl(context_->home_country)); | 150 GURL request_url(BuildRequestUrl(context_->home_country)); |
128 DCHECK(request_url.is_valid()); | 151 DCHECK(request_url.is_valid()); |
129 | 152 |
130 // Reset will delete any previous fetcher, and we won't get any callback. | 153 // Reset will delete any previous fetcher, and we won't get any callback. |
131 search_term_fetcher_.reset( | 154 search_term_fetcher_.reset( |
132 net::URLFetcher::Create(kContextualSearchURLFetcherID, request_url, | 155 net::URLFetcher::Create(kContextualSearchURLFetcherID, request_url, |
133 net::URLFetcher::GET, this).release()); | 156 net::URLFetcher::GET, this).release()); |
134 search_term_fetcher_->SetRequestContext(url_request_context_); | 157 search_term_fetcher_->SetRequestContext(url_request_context_); |
135 | 158 |
(...skipping 23 matching lines...) Expand all Loading... | |
159 if (source->GetStatus().is_success() && response_code == net::HTTP_OK) { | 182 if (source->GetStatus().is_success() && response_code == net::HTTP_OK) { |
160 std::string response; | 183 std::string response; |
161 bool has_string_response = source->GetResponseAsString(&response); | 184 bool has_string_response = source->GetResponseAsString(&response); |
162 DCHECK(has_string_response); | 185 DCHECK(has_string_response); |
163 if (has_string_response) { | 186 if (has_string_response) { |
164 resolved_search_term = | 187 resolved_search_term = |
165 GetResolvedSearchTermFromJson(response_code, response); | 188 GetResolvedSearchTermFromJson(response_code, response); |
166 } | 189 } |
167 } | 190 } |
168 search_term_callback_.Run(*resolved_search_term); | 191 search_term_callback_.Run(*resolved_search_term); |
169 | |
170 // The ContextualSearchContext is consumed once the request has completed. | |
171 context_.reset(); | |
172 } | 192 } |
173 | 193 |
174 std::unique_ptr<ResolvedSearchTerm> | 194 std::unique_ptr<ResolvedSearchTerm> |
175 ContextualSearchDelegate::GetResolvedSearchTermFromJson( | 195 ContextualSearchDelegate::GetResolvedSearchTermFromJson( |
176 int response_code, | 196 int response_code, |
177 const std::string& json_string) { | 197 const std::string& json_string) { |
178 std::string search_term; | 198 std::string search_term; |
179 std::string display_text; | 199 std::string display_text; |
180 std::string alternate_term; | 200 std::string alternate_term; |
181 std::string mid; | 201 std::string mid; |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
263 if (!replacement_url.empty()) { | 283 if (!replacement_url.empty()) { |
264 size_t pos = request.find(kContextualSearchServerEndpoint); | 284 size_t pos = request.find(kContextualSearchServerEndpoint); |
265 if (pos != std::string::npos) { | 285 if (pos != std::string::npos) { |
266 request.replace(0, pos + strlen(kContextualSearchServerEndpoint), | 286 request.replace(0, pos + strlen(kContextualSearchServerEndpoint), |
267 replacement_url); | 287 replacement_url); |
268 } | 288 } |
269 } | 289 } |
270 return request; | 290 return request; |
271 } | 291 } |
272 | 292 |
273 void ContextualSearchDelegate::GatherSurroundingTextWithCallback( | 293 void ContextualSearchDelegate::OnTextSurroundingSelectionAvailable( |
274 const std::string& selection, | |
275 const std::string& home_country, | |
276 content::WebContents* web_contents, | |
277 bool may_send_base_page_url, | |
278 HandleSurroundingsCallback callback) { | |
279 // Immediately cancel any request that's in flight, since we're building a new | |
280 // context (and the response disposes of any existing context). | |
281 search_term_fetcher_.reset(); | |
282 BuildContext(selection, home_country, web_contents, may_send_base_page_url); | |
283 DCHECK(web_contents); | |
284 RenderFrameHost* focused_frame = web_contents->GetFocusedFrame(); | |
285 if (focused_frame) { | |
286 focused_frame->RequestTextSurroundingSelection( | |
287 callback, field_trial_->GetSurroundingSize()); | |
288 } else { | |
289 callback.Run(base::string16(), 0, 0); | |
290 } | |
291 } | |
292 | |
293 void ContextualSearchDelegate::BuildContext(const std::string& selection, | |
294 const std::string& home_country, | |
295 content::WebContents* web_contents, | |
296 bool may_send_base_page_url) { | |
297 // Decide if the URL should be sent with the context. | |
298 GURL page_url(web_contents->GetURL()); | |
299 GURL url_to_send; | |
300 if (may_send_base_page_url && | |
301 CanSendPageURL(page_url, ProfileManager::GetActiveUserProfile(), | |
302 template_url_service_)) { | |
303 url_to_send = page_url; | |
304 } | |
305 std::string encoding(web_contents->GetEncoding()); | |
306 context_.reset(new ContextualSearchContext(selection, home_country, | |
307 url_to_send, encoding)); | |
308 } | |
309 | |
310 void ContextualSearchDelegate::StartSearchTermRequestFromSelection( | |
311 const base::string16& surrounding_text, | 294 const base::string16& surrounding_text, |
312 int start_offset, | 295 int start_offset, |
313 int end_offset) { | 296 int end_offset) { |
314 // TODO(donnd): figure out how to gather text surrounding the selection | 297 SaveSurroundingText(surrounding_text, start_offset, end_offset); |
315 // for other purposes too: e.g. to determine if we should select the | 298 if (!context_->IsBrief()) |
316 // word where the user tapped. | |
317 if (context_.get()) { | |
318 SaveSurroundingText(surrounding_text, start_offset, end_offset); | |
319 SendSurroundingText(kSurroundingSizeForUI); | 299 SendSurroundingText(kSurroundingSizeForUI); |
320 ContinueSearchTermResolutionRequest(); | |
321 } else { | |
322 DVLOG(1) << "ctxs: Null context, ignored!"; | |
323 } | |
324 } | 300 } |
325 | 301 |
326 void ContextualSearchDelegate::SaveSurroundingText( | 302 void ContextualSearchDelegate::SaveSurroundingText( |
327 const base::string16& surrounding_text, | 303 const base::string16& surrounding_text, |
328 int start_offset, | 304 int start_offset, |
329 int end_offset) { | 305 int end_offset) { |
330 DCHECK(context_.get()); | 306 DCHECK(context_); |
331 // Sometimes the surroundings are 0, 0, '', so fall back on the selection. | 307 // Sometimes the surroundings are 0, 0, '', so fall back on the selection. |
332 // See crbug.com/393100. | 308 // See crbug.com/393100. |
333 if (start_offset == 0 && end_offset == 0 && surrounding_text.length() == 0) { | 309 if (start_offset == 0 && end_offset == 0 && surrounding_text.length() == 0) { |
334 context_->surrounding_text = base::UTF8ToUTF16(context_->selected_text); | 310 context_->surrounding_text = base::UTF8ToUTF16(context_->selected_text); |
335 context_->start_offset = 0; | 311 context_->start_offset = 0; |
336 context_->end_offset = context_->selected_text.length(); | 312 context_->end_offset = context_->selected_text.length(); |
337 } else { | 313 } else { |
338 context_->surrounding_text = surrounding_text; | 314 context_->surrounding_text = surrounding_text; |
339 context_->start_offset = start_offset; | 315 context_->start_offset = start_offset; |
340 context_->end_offset = end_offset; | 316 context_->end_offset = end_offset; |
341 } | 317 } |
342 | 318 |
343 // Pin the start and end offsets to ensure they point within the string. | 319 // Pin the start and end offsets to ensure they point within the string. |
344 int surrounding_length = context_->surrounding_text.length(); | 320 int surrounding_length = context_->surrounding_text.length(); |
345 context_->start_offset = | 321 context_->start_offset = |
346 std::min(surrounding_length, std::max(0, context_->start_offset)); | 322 std::min(surrounding_length, std::max(0, context_->start_offset)); |
347 context_->end_offset = | 323 context_->end_offset = |
348 std::min(surrounding_length, std::max(0, context_->end_offset)); | 324 std::min(surrounding_length, std::max(0, context_->end_offset)); |
349 | 325 |
350 // Call the Icing callback with a shortened copy of the surroundings. | 326 // Call the Icing callback with a shortened copy of the surroundings. |
351 int icing_surrounding_size = field_trial_->GetIcingSurroundingSize(); | 327 int icing_surrounding_size = field_trial_->GetIcingSurroundingSize(); |
352 size_t selection_start = context_->start_offset; | 328 size_t selection_start = context_->start_offset; |
353 size_t selection_end = context_->end_offset; | 329 size_t selection_end = context_->end_offset; |
354 if (icing_surrounding_size >= 0 && selection_start < selection_end) { | 330 if (icing_surrounding_size >= 0 && selection_start <= selection_end) { |
355 int icing_padding_each_side = icing_surrounding_size / 2; | 331 int icing_padding_each_side = icing_surrounding_size / 2; |
356 base::string16 icing_surrounding_text = SurroundingTextForIcing( | 332 base::string16 icing_surrounding_text = SurroundingTextForIcing( |
357 context_->surrounding_text, icing_padding_each_side, &selection_start, | 333 context_->surrounding_text, icing_padding_each_side, &selection_start, |
358 &selection_end); | 334 &selection_end); |
359 if (selection_start < selection_end) | 335 if (selection_start <= selection_end) |
360 icing_callback_.Run(context_->encoding, icing_surrounding_text, | 336 icing_callback_.Run(context_->encoding, icing_surrounding_text, |
361 selection_start, selection_end); | 337 selection_start, selection_end); |
362 } | 338 } |
363 } | 339 } |
364 | 340 |
365 void ContextualSearchDelegate::SendSurroundingText(int max_surrounding_chars) { | 341 void ContextualSearchDelegate::SendSurroundingText(int max_surrounding_chars) { |
366 const base::string16& surrounding = context_->surrounding_text; | 342 const base::string16& surrounding = context_->surrounding_text; |
367 | 343 |
368 // Determine the text after the selection. | 344 // Determine the text after the selection. |
369 int surrounding_length = surrounding.length(); // Cast to int. | 345 int surrounding_length = surrounding.length(); // Cast to int. |
(...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
599 end_offset -= trim; | 575 end_offset -= trim; |
600 } | 576 } |
601 if (result_text.length() > end_offset + padding_each_side_pinned) { | 577 if (result_text.length() > end_offset + padding_each_side_pinned) { |
602 // Trim the end. | 578 // Trim the end. |
603 result_text = result_text.substr(0, end_offset + padding_each_side_pinned); | 579 result_text = result_text.substr(0, end_offset + padding_each_side_pinned); |
604 } | 580 } |
605 *start = start_offset; | 581 *start = start_offset; |
606 *end = end_offset; | 582 *end = end_offset; |
607 return result_text; | 583 return result_text; |
608 } | 584 } |
OLD | NEW |