Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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/string16.h" | 10 #include "base/string16.h" |
| (...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 154 // whatever we do here! | 154 // whatever we do here! |
| 155 // | 155 // |
| 156 // TODO(pkasting): http://b/1112681 If someday we remember usage frequency for | 156 // TODO(pkasting): http://b/1112681 If someday we remember usage frequency for |
| 157 // keywords, we might suggest keywords that haven't even been partially typed, | 157 // keywords, we might suggest keywords that haven't even been partially typed, |
| 158 // if the user uses them enough and isn't obviously typing something else. In | 158 // if the user uses them enough and isn't obviously typing something else. In |
| 159 // this case we'd consider all input here to be query input. | 159 // this case we'd consider all input here to be query input. |
| 160 string16 keyword, remaining_input; | 160 string16 keyword, remaining_input; |
| 161 if (!ExtractKeywordFromInput(input, &keyword, &remaining_input)) | 161 if (!ExtractKeywordFromInput(input, &keyword, &remaining_input)) |
| 162 return; | 162 return; |
| 163 | 163 |
| 164 // Make sure the model is loaded. This is cheap and quickly bails out if | 164 // Make sure the model is loaded. This is cheap and quickly bails out if |
|
Peter Kasting
2011/07/27 20:18:25
Nit: I think we should factor this into some publi
| |
| 165 // the model is already loaded. | 165 // the model is already loaded. |
| 166 TemplateURLService* model = | 166 TemplateURLService* model = |
| 167 profile_ ? | 167 profile_ ? |
| 168 TemplateURLServiceFactory::GetForProfile(profile_) : | 168 TemplateURLServiceFactory::GetForProfile(profile_) : |
| 169 model_; | 169 model_; |
| 170 DCHECK(model); | 170 DCHECK(model); |
| 171 model->Load(); | 171 model->Load(); |
| 172 | 172 |
| 173 // Get the best matches for this keyword. | 173 // Get the best matches for this keyword. |
| 174 // | 174 // |
| 175 // NOTE: We could cache the previous keywords and reuse them here in the | 175 // NOTE: We could cache the previous keywords and reuse them here in the |
| 176 // |minimal_changes| case, but since we'd still have to recalculate their | 176 // |minimal_changes| case, but since we'd still have to recalculate their |
| 177 // relevances and we can just recreate the results synchronously anyway, we | 177 // relevances and we can just recreate the results synchronously anyway, we |
| 178 // don't bother. | 178 // don't bother. |
| 179 // | 179 // |
| 180 // TODO(pkasting): http://b/893701 We should remember the user's use of a | 180 // TODO(pkasting): http://b/893701 We should remember the user's use of a |
| 181 // search query both from the autocomplete popup and from web pages | 181 // search query both from the autocomplete popup and from web pages |
| 182 // themselves. | 182 // themselves. |
| 183 std::vector<string16> keyword_matches; | 183 std::vector<string16> keyword_matches; |
| 184 model->FindMatchingKeywords(keyword, | 184 model->FindMatchingKeywords(keyword, |
| 185 !remaining_input.empty(), | 185 !remaining_input.empty(), |
| 186 &keyword_matches); | 186 &keyword_matches); |
| 187 | 187 |
| 188 // Prune any extension keywords that are disallowed in incognito mode (if | |
| 189 // we're incognito), or disabled. | |
| 190 for (std::vector<string16>::iterator i(keyword_matches.begin()); | 188 for (std::vector<string16>::iterator i(keyword_matches.begin()); |
| 191 i != keyword_matches.end(); ) { | 189 i != keyword_matches.end(); ) { |
| 192 const TemplateURL* template_url(model->GetTemplateURLForKeyword(*i)); | 190 const TemplateURL* template_url(model->GetTemplateURLForKeyword(*i)); |
| 191 | |
| 192 // Prune any extension keywords that are disallowed in incognito mode (if | |
| 193 // we're incognito), or disabled. | |
| 193 if (profile_ && | 194 if (profile_ && |
| 194 input.matches_requested() == AutocompleteInput::ALL_MATCHES && | 195 input.matches_requested() == AutocompleteInput::ALL_MATCHES && |
| 195 template_url->IsExtensionKeyword()) { | 196 template_url->IsExtensionKeyword()) { |
| 196 ExtensionService* service = profile_->GetExtensionService(); | 197 ExtensionService* service = profile_->GetExtensionService(); |
| 197 const Extension* extension = service->GetExtensionById( | 198 const Extension* extension = service->GetExtensionById( |
| 198 template_url->GetExtensionId(), false); | 199 template_url->GetExtensionId(), false); |
| 199 bool enabled = | 200 bool enabled = |
| 200 extension && (!profile_->IsOffTheRecord() || | 201 extension && (!profile_->IsOffTheRecord() || |
| 201 service->IsIncognitoEnabled(extension->id())); | 202 service->IsIncognitoEnabled(extension->id())); |
| 202 if (!enabled) { | 203 if (!enabled) { |
| 203 i = keyword_matches.erase(i); | 204 i = keyword_matches.erase(i); |
| 204 continue; | 205 continue; |
| 205 } | 206 } |
| 206 } | 207 } |
| 208 | |
| 209 // Prune any substituting keywords if there is no substitution. | |
| 210 if (TemplateURL::SupportsReplacement(template_url) && | |
| 211 !input.allow_exact_keyword_match()) { | |
| 212 i = keyword_matches.erase(i); | |
| 213 continue; | |
| 214 } | |
| 215 | |
| 207 ++i; | 216 ++i; |
| 208 } | 217 } |
| 209 if (keyword_matches.empty()) | 218 if (keyword_matches.empty()) |
| 210 return; | 219 return; |
| 211 std::sort(keyword_matches.begin(), keyword_matches.end(), CompareQuality()); | 220 std::sort(keyword_matches.begin(), keyword_matches.end(), CompareQuality()); |
| 212 | 221 |
| 213 // Limit to one exact or three inexact matches, and mark them up for display | 222 // Limit to one exact or three inexact matches, and mark them up for display |
| 214 // in the autocomplete popup. | 223 // in the autocomplete popup. |
| 215 // Any exact match is going to be the highest quality match, and thus at the | 224 // Any exact match is going to be the highest quality match, and thus at the |
| 216 // front of our vector. | 225 // front of our vector. |
| (...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 383 return (type == AutocompleteInput::URL) ? 700 : 450; | 392 return (type == AutocompleteInput::URL) ? 700 : 450; |
| 384 if (!supports_replacement || (allow_exact_keyword_match && prefer_keyword)) | 393 if (!supports_replacement || (allow_exact_keyword_match && prefer_keyword)) |
| 385 return 1500; | 394 return 1500; |
| 386 return (allow_exact_keyword_match && (type == AutocompleteInput::QUERY)) ? | 395 return (allow_exact_keyword_match && (type == AutocompleteInput::QUERY)) ? |
| 387 1450 : 1100; | 396 1450 : 1100; |
| 388 } | 397 } |
| 389 | 398 |
| 390 AutocompleteMatch KeywordProvider::CreateAutocompleteMatch( | 399 AutocompleteMatch KeywordProvider::CreateAutocompleteMatch( |
| 391 TemplateURLService* model, | 400 TemplateURLService* model, |
| 392 const string16& keyword, | 401 const string16& keyword, |
| 402 const AutocompleteInput& input) { | |
| 403 return CreateAutocompleteMatch(model, keyword, input, keyword.size(), | |
| 404 string16(), 0); | |
| 405 } | |
| 406 | |
| 407 AutocompleteMatch KeywordProvider::CreateAutocompleteMatch( | |
| 408 TemplateURLService* model, | |
| 409 const string16& keyword, | |
| 393 const AutocompleteInput& input, | 410 const AutocompleteInput& input, |
| 394 size_t prefix_length, | 411 size_t prefix_length, |
| 395 const string16& remaining_input, | 412 const string16& remaining_input, |
| 396 int relevance) { | 413 int relevance) { |
| 397 DCHECK(model); | 414 DCHECK(model); |
| 398 // Get keyword data from data store. | 415 // Get keyword data from data store. |
| 399 const TemplateURL* element( | 416 const TemplateURL* element( |
| 400 model->GetTemplateURLForKeyword(keyword)); | 417 model->GetTemplateURLForKeyword(keyword)); |
| 401 DCHECK(element && element->url()); | 418 DCHECK(element && element->url()); |
| 402 const bool supports_replacement = element->url()->SupportsReplacement(); | 419 const bool supports_replacement = element->url()->SupportsReplacement(); |
| 403 | 420 |
| 404 // Create an edit entry of "[keyword] [remaining input]". This is helpful | 421 // Create an edit entry of "[keyword] [remaining input]". This is helpful |
| 405 // even when [remaining input] is empty, as the user can select the popup | 422 // even when [remaining input] is empty, as the user can select the popup |
| 406 // choice and immediately begin typing in query input. | 423 // choice and immediately begin typing in query input. |
| 407 const bool keyword_complete = (prefix_length == keyword.length()); | 424 const bool keyword_complete = (prefix_length == keyword.length()); |
| 408 if (relevance < 0) { | 425 if (relevance < 0) { |
| 409 relevance = | 426 relevance = |
| 410 CalculateRelevance(input.type(), keyword_complete, | 427 CalculateRelevance(input.type(), keyword_complete, |
| 411 // When the user wants keyword matches to take | 428 // When the user wants keyword matches to take |
| 412 // preference, score them highly regardless of | 429 // preference, score them highly regardless of |
| 413 // whether the input provides query text. | 430 // whether the input provides query text. |
| 414 supports_replacement, input.prefer_keyword(), | 431 supports_replacement, input.prefer_keyword(), |
| 415 input.allow_exact_keyword_match()); | 432 input.allow_exact_keyword_match()); |
| 416 } | 433 } |
| 417 AutocompleteMatch result(this, relevance, false, | 434 AutocompleteMatch result(this, relevance, false, |
|
Peter Kasting
2011/07/27 20:18:25
Nit: While you're here, can you rename |result| to
| |
| 418 supports_replacement ? AutocompleteMatch::SEARCH_OTHER_ENGINE : | 435 supports_replacement ? AutocompleteMatch::SEARCH_OTHER_ENGINE : |
| 419 AutocompleteMatch::HISTORY_KEYWORD); | 436 AutocompleteMatch::HISTORY_KEYWORD); |
| 420 result.fill_into_edit.assign(keyword); | 437 result.fill_into_edit.assign(keyword); |
| 421 if (!remaining_input.empty() || !keyword_complete || supports_replacement) | 438 if (!remaining_input.empty() || !keyword_complete || supports_replacement) |
| 422 result.fill_into_edit.push_back(L' '); | 439 result.fill_into_edit.push_back(L' '); |
| 423 result.fill_into_edit.append(remaining_input); | 440 result.fill_into_edit.append(remaining_input); |
| 424 // If we wanted to set |result.inline_autocomplete_offset| correctly, we'd | 441 // If we wanted to set |result.inline_autocomplete_offset| correctly, we'd |
| 425 // need CleanUserInputKeyword() to return the amount of adjustment it's made | 442 // need CleanUserInputKeyword() to return the amount of adjustment it's made |
| 426 // to the user's input. Because right now inexact keyword matches can't score | 443 // to the user's input. Because right now inexact keyword matches can't score |
| 427 // more highly than a "what you typed" match from one of the other providers, | 444 // more highly than a "what you typed" match from one of the other providers, |
| 428 // we just don't bother to do this, and leave inline autocompletion off. | 445 // we just don't bother to do this, and leave inline autocompletion off. |
| 429 result.inline_autocomplete_offset = string16::npos; | 446 result.inline_autocomplete_offset = string16::npos; |
| 430 | 447 |
| 431 // Create destination URL and popup entry content by substituting user input | 448 // Create destination URL and popup entry content by substituting user input |
| 432 // into keyword templates. | 449 // into keyword templates. |
| 433 FillInURLAndContents(remaining_input, element, &result); | 450 FillInURLAndContents(remaining_input, element, &result); |
| 434 | 451 |
| 435 if (supports_replacement) | 452 result.template_url = element; |
|
Peter Kasting
2011/07/27 20:18:25
Do you know why the old code had this conditional?
aaron.randolph
2011/07/28 16:01:55
I think this may have been an artifact of some ear
| |
| 436 result.template_url = element; | 453 result.keyword = keyword; |
| 437 result.transition = PageTransition::KEYWORD; | 454 result.transition = PageTransition::KEYWORD; |
| 438 | 455 |
| 439 return result; | 456 return result; |
| 440 } | 457 } |
| 441 | 458 |
| 442 void KeywordProvider::Observe(int type, | 459 void KeywordProvider::Observe(int type, |
| 443 const NotificationSource& source, | 460 const NotificationSource& source, |
| 444 const NotificationDetails& details) { | 461 const NotificationDetails& details) { |
| 445 TemplateURLService* model = | 462 TemplateURLService* model = |
| 446 profile_ ? TemplateURLServiceFactory::GetForProfile(profile_) : model_; | 463 profile_ ? TemplateURLServiceFactory::GetForProfile(profile_) : model_; |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 530 } | 547 } |
| 531 | 548 |
| 532 void KeywordProvider::MaybeEndExtensionKeywordMode() { | 549 void KeywordProvider::MaybeEndExtensionKeywordMode() { |
| 533 if (!current_keyword_extension_id_.empty()) { | 550 if (!current_keyword_extension_id_.empty()) { |
| 534 ExtensionOmniboxEventRouter::OnInputCancelled( | 551 ExtensionOmniboxEventRouter::OnInputCancelled( |
| 535 profile_, current_keyword_extension_id_); | 552 profile_, current_keyword_extension_id_); |
| 536 | 553 |
| 537 current_keyword_extension_id_.clear(); | 554 current_keyword_extension_id_.clear(); |
| 538 } | 555 } |
| 539 } | 556 } |
| OLD | NEW |