Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/autocomplete/keyword_provider.h" | 5 #include "chrome/browser/autocomplete/keyword_provider.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <vector> | 8 #include <vector> |
| 9 | 9 |
| 10 #include "base/strings/string16.h" | 10 #include "base/strings/string16.h" |
| 11 #include "base/strings/string_util.h" | 11 #include "base/strings/string_util.h" |
| 12 #include "base/strings/utf_string_conversions.h" | 12 #include "base/strings/utf_string_conversions.h" |
| 13 #include "chrome/browser/autocomplete/keyword_extensions_delegate.h" | 13 #include "chrome/browser/autocomplete/keyword_extensions_delegate.h" |
| 14 #include "chrome/browser/chrome_notification_types.h" | |
| 15 #include "chrome/browser/profiles/profile.h" | |
| 16 #include "chrome/browser/search_engines/template_url_service_factory.h" | |
| 17 #include "components/metrics/proto/omnibox_input_type.pb.h" | 14 #include "components/metrics/proto/omnibox_input_type.pb.h" |
| 18 #include "components/omnibox/autocomplete_match.h" | 15 #include "components/omnibox/autocomplete_match.h" |
| 19 #include "components/omnibox/autocomplete_provider_listener.h" | 16 #include "components/omnibox/autocomplete_provider_listener.h" |
| 20 #include "components/search_engines/template_url.h" | 17 #include "components/search_engines/template_url.h" |
| 21 #include "components/search_engines/template_url_service.h" | 18 #include "components/search_engines/template_url_service.h" |
| 22 #include "content/public/browser/notification_details.h" | |
| 23 #include "content/public/browser/notification_source.h" | |
| 24 #include "extensions/browser/extension_system.h" | |
| 25 #include "grit/generated_resources.h" | 19 #include "grit/generated_resources.h" |
| 26 #include "net/base/escape.h" | 20 #include "net/base/escape.h" |
| 27 #include "net/base/net_util.h" | 21 #include "net/base/net_util.h" |
| 28 #include "ui/base/l10n/l10n_util.h" | 22 #include "ui/base/l10n/l10n_util.h" |
| 29 | 23 |
| 30 #if defined(ENABLE_EXTENSIONS) | |
| 31 #include "chrome/browser/autocomplete/keyword_extensions_delegate_impl.h" | |
| 32 #endif | |
| 33 | |
| 34 namespace { | 24 namespace { |
| 35 | 25 |
| 36 // Helper functor for Start(), for sorting keyword matches by quality. | 26 // Helper functor for Start(), for sorting keyword matches by quality. |
| 37 class CompareQuality { | 27 class CompareQuality { |
| 38 public: | 28 public: |
| 39 // A keyword is of higher quality when a greater fraction of it has been | 29 // A keyword is of higher quality when a greater fraction of it has been |
| 40 // typed, that is, when it is shorter. | 30 // typed, that is, when it is shorter. |
| 41 // | 31 // |
| 42 // TODO(pkasting): Most recent and most frequent keywords are probably | 32 // TODO(pkasting): Most recent and most frequent keywords are probably |
| 43 // better rankings than the fraction of the keyword typed. We should | 33 // better rankings than the fraction of the keyword typed. We should |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 72 if (delegate_) | 62 if (delegate_) |
| 73 delegate_->MaybeEndExtensionKeywordMode(); | 63 delegate_->MaybeEndExtensionKeywordMode(); |
| 74 } | 64 } |
| 75 | 65 |
| 76 void ScopedEndExtensionKeywordMode::StayInKeywordMode() { | 66 void ScopedEndExtensionKeywordMode::StayInKeywordMode() { |
| 77 delegate_ = NULL; | 67 delegate_ = NULL; |
| 78 } | 68 } |
| 79 | 69 |
| 80 } // namespace | 70 } // namespace |
| 81 | 71 |
| 82 KeywordProvider::KeywordProvider(AutocompleteProviderListener* listener, | 72 KeywordProvider::KeywordProvider( |
| 83 Profile* profile) | 73 AutocompleteProviderListener* listener, |
| 74 TemplateURLService* model) | |
| 84 : AutocompleteProvider(AutocompleteProvider::TYPE_KEYWORD), | 75 : AutocompleteProvider(AutocompleteProvider::TYPE_KEYWORD), |
| 85 listener_(listener), | 76 listener_(listener), |
| 86 profile_(profile), | |
| 87 model_(NULL) { | |
| 88 #if defined(ENABLE_EXTENSIONS) | |
| 89 extensions_delegate_.reset(new KeywordExtensionsDelegateImpl(this)); | |
| 90 #endif | |
| 91 } | |
| 92 | |
| 93 KeywordProvider::KeywordProvider(AutocompleteProviderListener* listener, | |
| 94 TemplateURLService* model) | |
| 95 : AutocompleteProvider(AutocompleteProvider::TYPE_KEYWORD), | |
| 96 listener_(listener), | |
| 97 profile_(NULL), | |
| 98 model_(model) { | 77 model_(model) { |
| 99 } | 78 } |
| 100 | 79 |
| 80 void KeywordProvider::SetExtensionsDelegate( | |
| 81 scoped_ptr<KeywordExtensionsDelegate> extensions_delegate) { | |
| 82 extensions_delegate_ = extensions_delegate.Pass(); | |
|
Peter Kasting
2014/08/12 18:24:11
Nit: This could probably be inlined into the heade
hashimoto
2014/08/13 02:22:40
Done.
| |
| 83 } | |
| 84 | |
| 101 // static | 85 // static |
| 102 base::string16 KeywordProvider::SplitKeywordFromInput( | 86 base::string16 KeywordProvider::SplitKeywordFromInput( |
| 103 const base::string16& input, | 87 const base::string16& input, |
| 104 bool trim_leading_whitespace, | 88 bool trim_leading_whitespace, |
| 105 base::string16* remaining_input) { | 89 base::string16* remaining_input) { |
| 106 // Find end of first token. The AutocompleteController has trimmed leading | 90 // Find end of first token. The AutocompleteController has trimmed leading |
| 107 // whitespace, so we need not skip over that. | 91 // whitespace, so we need not skip over that. |
| 108 const size_t first_white(input.find_first_of(base::kWhitespaceUTF16)); | 92 const size_t first_white(input.find_first_of(base::kWhitespaceUTF16)); |
| 109 DCHECK_NE(0U, first_white); | 93 DCHECK_NE(0U, first_white); |
| 110 if (first_white == base::string16::npos) | 94 if (first_white == base::string16::npos) |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 196 // Don't provide a keyword if it doesn't support replacement. | 180 // Don't provide a keyword if it doesn't support replacement. |
| 197 const TemplateURL* const template_url = | 181 const TemplateURL* const template_url = |
| 198 url_service->GetTemplateURLForKeyword(keyword); | 182 url_service->GetTemplateURLForKeyword(keyword); |
| 199 if (!template_url || | 183 if (!template_url || |
| 200 !template_url->SupportsReplacement(url_service->search_terms_data())) | 184 !template_url->SupportsReplacement(url_service->search_terms_data())) |
| 201 return base::string16(); | 185 return base::string16(); |
| 202 | 186 |
| 203 // Don't provide a keyword for inactive/disabled extension keywords. | 187 // Don't provide a keyword for inactive/disabled extension keywords. |
| 204 if ((template_url->GetType() == TemplateURL::OMNIBOX_API_EXTENSION) && | 188 if ((template_url->GetType() == TemplateURL::OMNIBOX_API_EXTENSION) && |
| 205 extensions_delegate_ && | 189 extensions_delegate_ && |
| 206 !extensions_delegate_->IsEnabledExtension( | 190 !extensions_delegate_->IsEnabledExtension(template_url->GetExtensionId())) |
| 207 profile_, template_url->GetExtensionId())) | |
| 208 return base::string16(); | 191 return base::string16(); |
| 209 | 192 |
| 210 return keyword; | 193 return keyword; |
| 211 } | 194 } |
| 212 | 195 |
| 213 AutocompleteMatch KeywordProvider::CreateVerbatimMatch( | 196 AutocompleteMatch KeywordProvider::CreateVerbatimMatch( |
| 214 const base::string16& text, | 197 const base::string16& text, |
| 215 const base::string16& keyword, | 198 const base::string16& keyword, |
| 216 const AutocompleteInput& input) { | 199 const AutocompleteInput& input) { |
| 217 // A verbatim match is allowed to be the default match. | 200 // A verbatim match is allowed to be the default match. |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 263 TemplateURLService::TemplateURLVector matches; | 246 TemplateURLService::TemplateURLVector matches; |
| 264 GetTemplateURLService()->FindMatchingKeywords( | 247 GetTemplateURLService()->FindMatchingKeywords( |
| 265 keyword, !remaining_input.empty(), &matches); | 248 keyword, !remaining_input.empty(), &matches); |
| 266 | 249 |
| 267 for (TemplateURLService::TemplateURLVector::iterator i(matches.begin()); | 250 for (TemplateURLService::TemplateURLVector::iterator i(matches.begin()); |
| 268 i != matches.end(); ) { | 251 i != matches.end(); ) { |
| 269 const TemplateURL* template_url = *i; | 252 const TemplateURL* template_url = *i; |
| 270 | 253 |
| 271 // Prune any extension keywords that are disallowed in incognito mode (if | 254 // Prune any extension keywords that are disallowed in incognito mode (if |
| 272 // we're incognito), or disabled. | 255 // we're incognito), or disabled. |
| 273 if (profile_ && | 256 if (template_url->GetType() == TemplateURL::OMNIBOX_API_EXTENSION && |
| 274 (template_url->GetType() == TemplateURL::OMNIBOX_API_EXTENSION) && | |
| 275 extensions_delegate_ && | 257 extensions_delegate_ && |
| 276 !extensions_delegate_->IsEnabledExtension( | 258 !extensions_delegate_->IsEnabledExtension( |
| 277 profile_, template_url->GetExtensionId())) { | 259 template_url->GetExtensionId())) { |
| 278 i = matches.erase(i); | 260 i = matches.erase(i); |
| 279 continue; | 261 continue; |
| 280 } | 262 } |
| 281 | 263 |
| 282 // Prune any substituting keywords if there is no substitution. | 264 // Prune any substituting keywords if there is no substitution. |
| 283 if (template_url->SupportsReplacement( | 265 if (template_url->SupportsReplacement( |
| 284 GetTemplateURLService()->search_terms_data()) && | 266 GetTemplateURLService()->search_terms_data()) && |
| 285 remaining_input.empty() && | 267 remaining_input.empty() && |
| 286 !input.allow_exact_keyword_match()) { | 268 !input.allow_exact_keyword_match()) { |
| 287 i = matches.erase(i); | 269 i = matches.erase(i); |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 313 | 295 |
| 314 // TODO(pkasting): We should probably check that if the user explicitly | 296 // TODO(pkasting): We should probably check that if the user explicitly |
| 315 // typed a scheme, that scheme matches the one in |template_url|. | 297 // typed a scheme, that scheme matches the one in |template_url|. |
| 316 | 298 |
| 317 // When creating an exact match (either for the keyword itself, no | 299 // When creating an exact match (either for the keyword itself, no |
| 318 // remaining query or an extension keyword, possibly with remaining | 300 // remaining query or an extension keyword, possibly with remaining |
| 319 // input), allow the match to be the default match. | 301 // input), allow the match to be the default match. |
| 320 matches_.push_back(CreateAutocompleteMatch( | 302 matches_.push_back(CreateAutocompleteMatch( |
| 321 template_url, input, keyword.length(), remaining_input, true, -1)); | 303 template_url, input, keyword.length(), remaining_input, true, -1)); |
| 322 | 304 |
| 323 if (profile_ && is_extension_keyword && extensions_delegate_) { | 305 if (is_extension_keyword && extensions_delegate_) { |
| 324 if (extensions_delegate_->Start(input, minimal_changes, template_url, | 306 if (extensions_delegate_->Start(input, minimal_changes, template_url, |
| 325 remaining_input)) | 307 remaining_input)) |
| 326 keyword_mode_toggle.StayInKeywordMode(); | 308 keyword_mode_toggle.StayInKeywordMode(); |
| 327 } | 309 } |
| 328 } else { | 310 } else { |
| 329 if (matches.size() > kMaxMatches) | 311 if (matches.size() > kMaxMatches) |
| 330 matches.erase(matches.begin() + kMaxMatches, matches.end()); | 312 matches.erase(matches.begin() + kMaxMatches, matches.end()); |
| 331 for (TemplateURLService::TemplateURLVector::const_iterator i( | 313 for (TemplateURLService::TemplateURLVector::const_iterator i( |
| 332 matches.begin()); i != matches.end(); ++i) { | 314 matches.begin()); i != matches.end(); ++i) { |
| 333 matches_.push_back(CreateAutocompleteMatch( | 315 matches_.push_back(CreateAutocompleteMatch( |
| (...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 480 remaining_input, | 462 remaining_input, |
| 481 &content_param_offsets)); | 463 &content_param_offsets)); |
| 482 DCHECK_EQ(2U, content_param_offsets.size()); | 464 DCHECK_EQ(2U, content_param_offsets.size()); |
| 483 AutocompleteMatch::ClassifyLocationInString(content_param_offsets[1], | 465 AutocompleteMatch::ClassifyLocationInString(content_param_offsets[1], |
| 484 remaining_input.length(), match->contents.length(), | 466 remaining_input.length(), match->contents.length(), |
| 485 ACMatchClassification::NONE, &match->contents_class); | 467 ACMatchClassification::NONE, &match->contents_class); |
| 486 } | 468 } |
| 487 } | 469 } |
| 488 | 470 |
| 489 TemplateURLService* KeywordProvider::GetTemplateURLService() const { | 471 TemplateURLService* KeywordProvider::GetTemplateURLService() const { |
| 490 TemplateURLService* service = profile_ ? | |
| 491 TemplateURLServiceFactory::GetForProfile(profile_) : model_; | |
| 492 // Make sure the model is loaded. This is cheap and quickly bails out if | 472 // Make sure the model is loaded. This is cheap and quickly bails out if |
| 493 // the model is already loaded. | 473 // the model is already loaded. |
| 494 DCHECK(service); | 474 model_->Load(); |
| 495 service->Load(); | 475 return model_; |
| 496 return service; | |
| 497 } | 476 } |
| OLD | NEW |