Chromium Code Reviews| 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 |