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" |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 79 // Helper functor for Start(), for sorting keyword matches by quality. | 79 // Helper functor for Start(), for sorting keyword matches by quality. |
| 80 class CompareQuality { | 80 class CompareQuality { |
| 81 public: | 81 public: |
| 82 // A keyword is of higher quality when a greater fraction of it has been | 82 // A keyword is of higher quality when a greater fraction of it has been |
| 83 // typed, that is, when it is shorter. | 83 // typed, that is, when it is shorter. |
| 84 // | 84 // |
| 85 // TODO(pkasting): http://b/740691 Most recent and most frequent keywords are | 85 // TODO(pkasting): http://b/740691 Most recent and most frequent keywords are |
| 86 // probably better rankings than the fraction of the keyword typed. We should | 86 // probably better rankings than the fraction of the keyword typed. We should |
| 87 // always put any exact matches first no matter what, since the code in | 87 // always put any exact matches first no matter what, since the code in |
| 88 // Start() assumes this (and it makes sense). | 88 // Start() assumes this (and it makes sense). |
| 89 bool operator()(const string16& keyword1, | 89 bool operator()(const TemplateURL* t_url1, const TemplateURL* t_url2) const { |
| 90 const string16& keyword2) const { | 90 return t_url1->keyword().length() < t_url2->keyword().length(); |
| 91 return keyword1.length() < keyword2.length(); | |
| 92 } | 91 } |
| 93 }; | 92 }; |
| 94 | 93 |
| 95 // We need our input IDs to be unique across all profiles, so we keep a global | 94 // We need our input IDs to be unique across all profiles, so we keep a global |
| 96 // UID that each provider uses. | 95 // UID that each provider uses. |
| 97 static int global_input_uid_; | 96 static int global_input_uid_; |
| 98 | 97 |
| 99 } // namespace | 98 } // namespace |
| 100 | 99 |
| 101 // static | 100 // static |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 209 return string16(); | 208 return string16(); |
| 210 } | 209 } |
| 211 | 210 |
| 212 return keyword; | 211 return keyword; |
| 213 } | 212 } |
| 214 | 213 |
| 215 AutocompleteMatch KeywordProvider::CreateAutocompleteMatch( | 214 AutocompleteMatch KeywordProvider::CreateAutocompleteMatch( |
| 216 const string16& text, | 215 const string16& text, |
| 217 const string16& keyword, | 216 const string16& keyword, |
| 218 const AutocompleteInput& input) { | 217 const AutocompleteInput& input) { |
| 219 return CreateAutocompleteMatch(GetTemplateURLService(), keyword, input, | 218 return CreateAutocompleteMatch( |
| 220 keyword.size(), SplitReplacementStringFromInput(text, true), 0); | 219 GetTemplateURLService()->GetTemplateURLForKeyword(keyword), input, |
| 220 keyword.length(), SplitReplacementStringFromInput(text, true), 0); | |
| 221 } | 221 } |
| 222 | 222 |
| 223 void KeywordProvider::Start(const AutocompleteInput& input, | 223 void KeywordProvider::Start(const AutocompleteInput& input, |
| 224 bool minimal_changes) { | 224 bool minimal_changes) { |
| 225 // This object ensures we end keyword mode if we exit the function without | 225 // This object ensures we end keyword mode if we exit the function without |
| 226 // toggling keyword mode to on. | 226 // toggling keyword mode to on. |
| 227 ScopedEndExtensionKeywordMode keyword_mode_toggle(this); | 227 ScopedEndExtensionKeywordMode keyword_mode_toggle(this); |
| 228 | 228 |
| 229 matches_.clear(); | 229 matches_.clear(); |
| 230 | 230 |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 246 // whatever we do here! | 246 // whatever we do here! |
| 247 // | 247 // |
| 248 // TODO(pkasting): http://b/1112681 If someday we remember usage frequency for | 248 // TODO(pkasting): http://b/1112681 If someday we remember usage frequency for |
| 249 // keywords, we might suggest keywords that haven't even been partially typed, | 249 // keywords, we might suggest keywords that haven't even been partially typed, |
| 250 // if the user uses them enough and isn't obviously typing something else. In | 250 // if the user uses them enough and isn't obviously typing something else. In |
| 251 // this case we'd consider all input here to be query input. | 251 // this case we'd consider all input here to be query input. |
| 252 string16 keyword, remaining_input; | 252 string16 keyword, remaining_input; |
| 253 if (!ExtractKeywordFromInput(input, &keyword, &remaining_input)) | 253 if (!ExtractKeywordFromInput(input, &keyword, &remaining_input)) |
| 254 return; | 254 return; |
| 255 | 255 |
| 256 TemplateURLService* model = GetTemplateURLService(); | |
| 257 | |
| 258 // Get the best matches for this keyword. | 256 // Get the best matches for this keyword. |
| 259 // | 257 // |
| 260 // NOTE: We could cache the previous keywords and reuse them here in the | 258 // NOTE: We could cache the previous keywords and reuse them here in the |
| 261 // |minimal_changes| case, but since we'd still have to recalculate their | 259 // |minimal_changes| case, but since we'd still have to recalculate their |
| 262 // relevances and we can just recreate the results synchronously anyway, we | 260 // relevances and we can just recreate the results synchronously anyway, we |
| 263 // don't bother. | 261 // don't bother. |
| 264 // | 262 // |
| 265 // TODO(pkasting): http://b/893701 We should remember the user's use of a | 263 // TODO(pkasting): http://b/893701 We should remember the user's use of a |
| 266 // search query both from the autocomplete popup and from web pages | 264 // search query both from the autocomplete popup and from web pages |
| 267 // themselves. | 265 // themselves. |
| 268 std::vector<string16> keyword_matches; | 266 TemplateURLService::TemplateURLVector matches; |
| 269 model->FindMatchingKeywords(keyword, | 267 GetTemplateURLService()->FindMatchingKeywords( |
| 270 !remaining_input.empty(), | 268 keyword, !remaining_input.empty(), &matches); |
| 271 &keyword_matches); | |
| 272 | 269 |
| 273 for (std::vector<string16>::iterator i(keyword_matches.begin()); | 270 for (TemplateURLService::TemplateURLVector::iterator i(matches.begin()); |
| 274 i != keyword_matches.end(); ) { | 271 i != matches.end(); ) { |
| 275 const TemplateURL* template_url = model->GetTemplateURLForKeyword(*i); | 272 const TemplateURL* template_url = *i; |
| 276 | 273 |
| 277 // Prune any extension keywords that are disallowed in incognito mode (if | 274 // Prune any extension keywords that are disallowed in incognito mode (if |
| 278 // we're incognito), or disabled. | 275 // we're incognito), or disabled. |
| 279 if (profile_ && template_url->IsExtensionKeyword()) { | 276 if (profile_ && template_url->IsExtensionKeyword()) { |
| 280 ExtensionService* service = extensions::ExtensionSystem::Get(profile_)-> | 277 ExtensionService* service = extensions::ExtensionSystem::Get(profile_)-> |
| 281 extension_service(); | 278 extension_service(); |
| 282 const extensions::Extension* extension = service->GetExtensionById( | 279 const extensions::Extension* extension = |
| 283 template_url->GetExtensionId(), false); | 280 service->GetExtensionById(template_url->GetExtensionId(), false); |
| 284 bool enabled = | 281 bool enabled = |
| 285 extension && (!profile_->IsOffTheRecord() || | 282 extension && (!profile_->IsOffTheRecord() || |
| 286 service->IsIncognitoEnabled(extension->id())); | 283 service->IsIncognitoEnabled(extension->id())); |
| 287 if (!enabled) { | 284 if (!enabled) { |
| 288 i = keyword_matches.erase(i); | 285 i = matches.erase(i); |
| 289 continue; | 286 continue; |
| 290 } | 287 } |
| 291 } | 288 } |
| 292 | 289 |
| 293 // Prune any substituting keywords if there is no substitution. | 290 // Prune any substituting keywords if there is no substitution. |
| 294 if (template_url->SupportsReplacement() && remaining_input.empty() && | 291 if (template_url->SupportsReplacement() && remaining_input.empty() && |
| 295 !input.allow_exact_keyword_match()) { | 292 !input.allow_exact_keyword_match()) { |
| 296 i = keyword_matches.erase(i); | 293 i = matches.erase(i); |
| 297 continue; | 294 continue; |
| 298 } | 295 } |
| 299 | 296 |
| 300 ++i; | 297 ++i; |
| 301 } | 298 } |
| 302 if (keyword_matches.empty()) | 299 if (matches.empty()) |
| 303 return; | 300 return; |
| 304 std::sort(keyword_matches.begin(), keyword_matches.end(), CompareQuality()); | 301 std::sort(matches.begin(), matches.end(), CompareQuality()); |
| 305 | 302 |
| 306 // Limit to one exact or three inexact matches, and mark them up for display | 303 // Limit to one exact or three inexact matches, and mark them up for display |
| 307 // in the autocomplete popup. | 304 // in the autocomplete popup. |
| 308 // Any exact match is going to be the highest quality match, and thus at the | 305 // Any exact match is going to be the highest quality match, and thus at the |
| 309 // front of our vector. | 306 // front of our vector. |
| 310 if (keyword_matches.front() == keyword) { | 307 if (matches.front()->keyword() == keyword) { |
| 311 const TemplateURL* template_url = model->GetTemplateURLForKeyword(keyword); | 308 const TemplateURL* template_url = matches.front(); |
| 312 const bool is_extension_keyword = template_url->IsExtensionKeyword(); | 309 const bool is_extension_keyword = template_url->IsExtensionKeyword(); |
| 313 | 310 |
| 314 // Only create an exact match if |remaining_input| is empty or if | 311 // Only create an exact match if |remaining_input| is empty or if |
| 315 // this is an extension keyword. If |remaining_input| is a | 312 // this is an extension keyword. If |remaining_input| is a |
| 316 // non-empty non-extension keyword (i.e., a regular keyword that | 313 // non-empty non-extension keyword (i.e., a regular keyword that |
| 317 // supports replacement and that has extra text following it), | 314 // supports replacement and that has extra text following it), |
| 318 // then SearchProvider creates the exact (a.k.a. verbatim) match. | 315 // then SearchProvider creates the exact (a.k.a. verbatim) match. |
| 319 if (!remaining_input.empty() && !is_extension_keyword) | 316 if (!remaining_input.empty() && !is_extension_keyword) |
| 320 return; | 317 return; |
| 321 | 318 |
| 322 // TODO(pkasting): We should probably check that if the user explicitly | 319 // TODO(pkasting): We should probably check that if the user explicitly |
| 323 // typed a scheme, that scheme matches the one in |template_url|. | 320 // typed a scheme, that scheme matches the one in |template_url|. |
| 324 matches_.push_back(CreateAutocompleteMatch(model, keyword, input, | 321 matches_.push_back(CreateAutocompleteMatch( |
| 325 keyword.length(), | 322 template_url, input, keyword.length(), remaining_input, -1)); |
| 326 remaining_input, -1)); | |
| 327 | 323 |
| 328 if (profile_ && is_extension_keyword) { | 324 if (profile_ && is_extension_keyword) { |
| 329 if (input.matches_requested() == AutocompleteInput::ALL_MATCHES) { | 325 if (input.matches_requested() == AutocompleteInput::ALL_MATCHES) { |
| 330 if (template_url->GetExtensionId() != current_keyword_extension_id_) | 326 if (template_url->GetExtensionId() != current_keyword_extension_id_) |
| 331 MaybeEndExtensionKeywordMode(); | 327 MaybeEndExtensionKeywordMode(); |
| 332 if (current_keyword_extension_id_.empty()) | 328 if (current_keyword_extension_id_.empty()) |
| 333 EnterExtensionKeywordMode(template_url->GetExtensionId()); | 329 EnterExtensionKeywordMode(template_url->GetExtensionId()); |
| 334 keyword_mode_toggle.StayInKeywordMode(); | 330 keyword_mode_toggle.StayInKeywordMode(); |
| 335 } | 331 } |
| 336 | 332 |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 357 profile_, template_url->GetExtensionId(), | 353 profile_, template_url->GetExtensionId(), |
| 358 UTF16ToUTF8(remaining_input), current_input_id_); | 354 UTF16ToUTF8(remaining_input), current_input_id_); |
| 359 | 355 |
| 360 // We only have to wait for suggest results if there are actually | 356 // We only have to wait for suggest results if there are actually |
| 361 // extensions listening for input changes. | 357 // extensions listening for input changes. |
| 362 if (have_listeners) | 358 if (have_listeners) |
| 363 done_ = false; | 359 done_ = false; |
| 364 } | 360 } |
| 365 } | 361 } |
| 366 } else { | 362 } else { |
| 367 if (keyword_matches.size() > kMaxMatches) { | 363 if (matches.size() > kMaxMatches) |
| 368 keyword_matches.erase(keyword_matches.begin() + kMaxMatches, | 364 matches.erase(matches.begin() + kMaxMatches, matches.end()); |
| 369 keyword_matches.end()); | 365 for (TemplateURLService::TemplateURLVector::const_iterator i( |
| 370 } | 366 matches.begin()); i != matches.end(); ++i) { |
| 371 for (std::vector<string16>::const_iterator i(keyword_matches.begin()); | 367 matches_.push_back(CreateAutocompleteMatch( |
| 372 i != keyword_matches.end(); ++i) { | 368 *i, input, keyword.length(), remaining_input, -1)); |
| 373 matches_.push_back(CreateAutocompleteMatch(model, *i, | |
| 374 input, keyword.length(), | |
| 375 remaining_input, -1)); | |
| 376 } | 369 } |
| 377 } | 370 } |
| 378 } | 371 } |
| 379 | 372 |
| 380 void KeywordProvider::Stop(bool clear_cached_results) { | 373 void KeywordProvider::Stop(bool clear_cached_results) { |
| 381 done_ = true; | 374 done_ = true; |
| 382 MaybeEndExtensionKeywordMode(); | 375 MaybeEndExtensionKeywordMode(); |
| 383 } | 376 } |
| 384 | 377 |
| 385 KeywordProvider::~KeywordProvider() {} | 378 KeywordProvider::~KeywordProvider() {} |
| 386 | 379 |
| 387 // static | 380 // static |
| 388 bool KeywordProvider::ExtractKeywordFromInput(const AutocompleteInput& input, | 381 bool KeywordProvider::ExtractKeywordFromInput(const AutocompleteInput& input, |
| 389 string16* keyword, | 382 string16* keyword, |
| 390 string16* remaining_input) { | 383 string16* remaining_input) { |
| 391 if ((input.type() == AutocompleteInput::INVALID) || | 384 if ((input.type() == AutocompleteInput::INVALID) || |
| 392 (input.type() == AutocompleteInput::FORCED_QUERY)) | 385 (input.type() == AutocompleteInput::FORCED_QUERY)) |
| 393 return false; | 386 return false; |
| 394 | 387 |
| 395 string16 trimmed_input; | 388 string16 trimmed_input; |
| 396 TrimWhitespace(input.text(), TRIM_TRAILING, &trimmed_input); | 389 TrimWhitespace(input.text(), TRIM_TRAILING, &trimmed_input); |
| 397 *keyword = TemplateURLService::CleanUserInputKeyword( | 390 *keyword = TemplateURLService::CleanUserInputKeyword( |
| 398 SplitKeywordFromInput(trimmed_input, true, remaining_input)); | 391 SplitKeywordFromInput(trimmed_input, true, remaining_input)); |
| 399 return !keyword->empty(); | 392 return !keyword->empty(); |
| 400 } | 393 } |
| 401 | 394 |
| 402 // static | 395 // static |
| 403 void KeywordProvider::FillInURLAndContents( | 396 int KeywordProvider::CalculateRelevance(AutocompleteInput::Type type, |
| 404 const string16& remaining_input, | 397 bool complete, |
| 405 const TemplateURL* element, | 398 bool supports_replacement, |
| 406 AutocompleteMatch* match) { | 399 bool prefer_keyword, |
| 400 bool allow_exact_keyword_match) { | |
| 401 // This function is responsible for scoring suggestions of keywords | |
| 402 // themselves and the suggestion of the verbatim query on an | |
| 403 // extension keyword. SearchProvider::CalculateRelevanceForKeywordVerbatim() | |
| 404 // scores verbatim query suggestions for non-extension keywords. | |
| 405 // These two functions are currently in sync, but there's no reason | |
| 406 // we couldn't decide in the future to score verbatim matches | |
| 407 // differently for extension and non-extension keywords. If you | |
| 408 // make such a change, however, you should update this comment to | |
| 409 // describe it, so it's clear why the functions diverge. | |
| 410 if (!complete) | |
| 411 return (type == AutocompleteInput::URL) ? 700 : 450; | |
| 412 if (!supports_replacement || (allow_exact_keyword_match && prefer_keyword)) | |
| 413 return 1500; | |
| 414 return (allow_exact_keyword_match && (type == AutocompleteInput::QUERY)) ? | |
| 415 1450 : 1100; | |
| 416 } | |
| 417 | |
| 418 // static | |
| 419 void KeywordProvider::FillInURLAndContents(const string16& remaining_input, | |
| 420 const TemplateURL* element, | |
| 421 AutocompleteMatch* match) { | |
| 407 DCHECK(!element->short_name().empty()); | 422 DCHECK(!element->short_name().empty()); |
| 408 const TemplateURLRef& element_ref = element->url_ref(); | 423 const TemplateURLRef& element_ref = element->url_ref(); |
| 409 DCHECK(element_ref.IsValid()); | 424 DCHECK(element_ref.IsValid()); |
| 410 int message_id = element->IsExtensionKeyword() ? | 425 int message_id = element->IsExtensionKeyword() ? |
| 411 IDS_EXTENSION_KEYWORD_COMMAND : IDS_KEYWORD_SEARCH; | 426 IDS_EXTENSION_KEYWORD_COMMAND : IDS_KEYWORD_SEARCH; |
| 412 if (remaining_input.empty()) { | 427 if (remaining_input.empty()) { |
| 413 // Allow extension keyword providers to accept empty string input. This is | 428 // Allow extension keyword providers to accept empty string input. This is |
| 414 // useful to allow extensions to do something in the case where no input is | 429 // useful to allow extensions to do something in the case where no input is |
| 415 // entered. | 430 // entered. |
| 416 if (element_ref.SupportsReplacement() && !element->IsExtensionKeyword()) { | 431 if (element_ref.SupportsReplacement() && !element->IsExtensionKeyword()) { |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 435 // input, but we rely on later canonicalization functions to do more | 450 // input, but we rely on later canonicalization functions to do more |
| 436 // fixup to make the URL valid if necessary. | 451 // fixup to make the URL valid if necessary. |
| 437 DCHECK(element_ref.SupportsReplacement()); | 452 DCHECK(element_ref.SupportsReplacement()); |
| 438 match->destination_url = GURL(element_ref.ReplaceSearchTerms( | 453 match->destination_url = GURL(element_ref.ReplaceSearchTerms( |
| 439 TemplateURLRef::SearchTermsArgs(remaining_input))); | 454 TemplateURLRef::SearchTermsArgs(remaining_input))); |
| 440 std::vector<size_t> content_param_offsets; | 455 std::vector<size_t> content_param_offsets; |
| 441 match->contents.assign(l10n_util::GetStringFUTF16(message_id, | 456 match->contents.assign(l10n_util::GetStringFUTF16(message_id, |
| 442 element->short_name(), | 457 element->short_name(), |
| 443 remaining_input, | 458 remaining_input, |
| 444 &content_param_offsets)); | 459 &content_param_offsets)); |
| 445 if (content_param_offsets.size() == 2) { | 460 DCHECK_EQ(2U, content_param_offsets.size()); |
| 446 AutocompleteMatch::ClassifyLocationInString(content_param_offsets[1], | 461 AutocompleteMatch::ClassifyLocationInString(content_param_offsets[1], |
| 447 remaining_input.length(), match->contents.length(), | 462 remaining_input.length(), match->contents.length(), |
| 448 ACMatchClassification::NONE, &match->contents_class); | 463 ACMatchClassification::NONE, &match->contents_class); |
| 449 } else { | |
| 450 // See comments on an identical NOTREACHED() in search_provider.cc. | |
| 451 NOTREACHED(); | |
| 452 } | |
| 453 } | 464 } |
| 454 } | 465 } |
| 455 | 466 |
| 456 // static | |
| 457 int KeywordProvider::CalculateRelevance(AutocompleteInput::Type type, | |
| 458 bool complete, | |
| 459 bool supports_replacement, | |
| 460 bool prefer_keyword, | |
| 461 bool allow_exact_keyword_match) { | |
| 462 // This function is responsible for scoring suggestions of keywords | |
| 463 // themselves and the suggestion of the verbatim query on an | |
| 464 // extension keyword. SearchProvider::CalculateRelevanceForKeywordVerbatim() | |
| 465 // scores verbatim query suggestions for non-extension keywords. | |
| 466 // These two functions are currently in sync, but there's no reason | |
| 467 // we couldn't decide in the future to score verbatim matches | |
| 468 // differently for extension and non-extension keywords. If you | |
| 469 // make such a change, however, you should update this comment to | |
| 470 // describe it, so it's clear why the functions diverge. | |
| 471 if (!complete) | |
| 472 return (type == AutocompleteInput::URL) ? 700 : 450; | |
| 473 if (!supports_replacement || (allow_exact_keyword_match && prefer_keyword)) | |
| 474 return 1500; | |
| 475 return (allow_exact_keyword_match && (type == AutocompleteInput::QUERY)) ? | |
| 476 1450 : 1100; | |
| 477 } | |
| 478 | |
| 479 AutocompleteMatch KeywordProvider::CreateAutocompleteMatch( | 467 AutocompleteMatch KeywordProvider::CreateAutocompleteMatch( |
| 480 TemplateURLService* model, | 468 const TemplateURL* template_url, |
| 481 const string16& keyword, | |
| 482 const AutocompleteInput& input, | 469 const AutocompleteInput& input, |
| 483 size_t prefix_length, | 470 size_t prefix_length, |
| 484 const string16& remaining_input, | 471 const string16& remaining_input, |
| 485 int relevance) { | 472 int relevance) { |
| 486 DCHECK(model); | 473 DCHECK(template_url); |
| 487 // Get keyword data from data store. | 474 const bool supports_replacement = |
| 488 TemplateURL* element = model->GetTemplateURLForKeyword(keyword); | 475 template_url->url_ref().SupportsReplacement(); |
| 489 DCHECK(element); | |
| 490 const bool supports_replacement = element->url_ref().SupportsReplacement(); | |
| 491 | 476 |
|
Jered
2013/06/28 21:57:28
Consider const string16& keyword = template_url()-
Peter Kasting
2013/06/28 22:16:02
Done.
| |
| 492 // Create an edit entry of "[keyword] [remaining input]". This is helpful | 477 // Create an edit entry of "[keyword] [remaining input]". This is helpful |
| 493 // even when [remaining input] is empty, as the user can select the popup | 478 // even when [remaining input] is empty, as the user can select the popup |
| 494 // choice and immediately begin typing in query input. | 479 // choice and immediately begin typing in query input. |
| 495 const bool keyword_complete = (prefix_length == keyword.length()); | 480 const bool keyword_complete = |
| 481 (prefix_length == template_url->keyword().length()); | |
| 496 if (relevance < 0) { | 482 if (relevance < 0) { |
| 497 relevance = | 483 relevance = |
| 498 CalculateRelevance(input.type(), keyword_complete, | 484 CalculateRelevance(input.type(), keyword_complete, |
| 499 // When the user wants keyword matches to take | 485 // When the user wants keyword matches to take |
| 500 // preference, score them highly regardless of | 486 // preference, score them highly regardless of |
| 501 // whether the input provides query text. | 487 // whether the input provides query text. |
| 502 supports_replacement, input.prefer_keyword(), | 488 supports_replacement, input.prefer_keyword(), |
| 503 input.allow_exact_keyword_match()); | 489 input.allow_exact_keyword_match()); |
| 504 } | 490 } |
| 505 AutocompleteMatch match(this, relevance, false, | 491 AutocompleteMatch match(this, relevance, false, |
| 506 supports_replacement ? AutocompleteMatchType::SEARCH_OTHER_ENGINE : | 492 supports_replacement ? AutocompleteMatchType::SEARCH_OTHER_ENGINE : |
| 507 AutocompleteMatchType::HISTORY_KEYWORD); | 493 AutocompleteMatchType::HISTORY_KEYWORD); |
| 508 match.fill_into_edit.assign(keyword); | 494 match.fill_into_edit = template_url->keyword(); |
| 509 if (!remaining_input.empty() || !keyword_complete || supports_replacement) | 495 if (!remaining_input.empty() || !keyword_complete || supports_replacement) |
| 510 match.fill_into_edit.push_back(L' '); | 496 match.fill_into_edit.push_back(L' '); |
| 511 match.fill_into_edit.append(remaining_input); | 497 match.fill_into_edit.append(remaining_input); |
| 512 // If we wanted to set |result.inline_autocomplete_offset| correctly, we'd | 498 // If we wanted to set |result.inline_autocomplete_offset| correctly, we'd |
| 513 // need CleanUserInputKeyword() to return the amount of adjustment it's made | 499 // need CleanUserInputKeyword() to return the amount of adjustment it's made |
| 514 // to the user's input. Because right now inexact keyword matches can't score | 500 // to the user's input. Because right now inexact keyword matches can't score |
| 515 // more highly than a "what you typed" match from one of the other providers, | 501 // more highly than a "what you typed" match from one of the other providers, |
| 516 // we just don't bother to do this, and leave inline autocompletion off. | 502 // we just don't bother to do this, and leave inline autocompletion off. |
| 517 match.inline_autocomplete_offset = string16::npos; | 503 match.inline_autocomplete_offset = string16::npos; |
| 518 | 504 |
| 519 // Create destination URL and popup entry content by substituting user input | 505 // Create destination URL and popup entry content by substituting user input |
| 520 // into keyword templates. | 506 // into keyword templates. |
| 521 FillInURLAndContents(remaining_input, element, &match); | 507 FillInURLAndContents(remaining_input, template_url, &match); |
| 522 | 508 |
| 523 match.keyword = keyword; | 509 match.keyword = template_url->keyword(); |
| 524 match.transition = content::PAGE_TRANSITION_KEYWORD; | 510 match.transition = content::PAGE_TRANSITION_KEYWORD; |
| 525 | 511 |
| 526 return match; | 512 return match; |
| 527 } | 513 } |
| 528 | 514 |
| 529 void KeywordProvider::Observe(int type, | 515 void KeywordProvider::Observe(int type, |
| 530 const content::NotificationSource& source, | 516 const content::NotificationSource& source, |
| 531 const content::NotificationDetails& details) { | 517 const content::NotificationDetails& details) { |
| 532 TemplateURLService* model = GetTemplateURLService(); | 518 TemplateURLService* model = GetTemplateURLService(); |
| 533 const AutocompleteInput& input = extension_suggest_last_input_; | 519 const AutocompleteInput& input = extension_suggest_last_input_; |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 578 const omnibox_api::SuggestResult& suggestion = | 564 const omnibox_api::SuggestResult& suggestion = |
| 579 *suggestions.suggest_results[i]; | 565 *suggestions.suggest_results[i]; |
| 580 // We want to order these suggestions in descending order, so start with | 566 // We want to order these suggestions in descending order, so start with |
| 581 // the relevance of the first result (added synchronously in Start()), | 567 // the relevance of the first result (added synchronously in Start()), |
| 582 // and subtract 1 for each subsequent suggestion from the extension. | 568 // and subtract 1 for each subsequent suggestion from the extension. |
| 583 // We know that |complete| is true, because we wouldn't get results from | 569 // We know that |complete| is true, because we wouldn't get results from |
| 584 // the extension unless the full keyword had been typed. | 570 // the extension unless the full keyword had been typed. |
| 585 int first_relevance = CalculateRelevance(input.type(), true, true, | 571 int first_relevance = CalculateRelevance(input.type(), true, true, |
| 586 input.prefer_keyword(), input.allow_exact_keyword_match()); | 572 input.prefer_keyword(), input.allow_exact_keyword_match()); |
| 587 extension_suggest_matches_.push_back(CreateAutocompleteMatch( | 573 extension_suggest_matches_.push_back(CreateAutocompleteMatch( |
| 588 model, keyword, input, keyword.length(), | 574 model->GetTemplateURLForKeyword(keyword), input, keyword.length(), |
|
Jered
2013/06/28 21:57:28
Move this outside the loop.
Peter Kasting
2013/06/28 22:16:02
Done. Nice catch.
| |
| 589 UTF8ToUTF16(suggestion.content), first_relevance - (i + 1))); | 575 UTF8ToUTF16(suggestion.content), first_relevance - (i + 1))); |
| 590 | 576 |
| 591 AutocompleteMatch* match = &extension_suggest_matches_.back(); | 577 AutocompleteMatch* match = &extension_suggest_matches_.back(); |
| 592 match->contents.assign(UTF8ToUTF16(suggestion.description)); | 578 match->contents.assign(UTF8ToUTF16(suggestion.description)); |
| 593 match->contents_class = | 579 match->contents_class = |
| 594 extensions::StyleTypesToACMatchClassifications(suggestion); | 580 extensions::StyleTypesToACMatchClassifications(suggestion); |
| 595 match->description.clear(); | 581 match->description.clear(); |
| 596 match->description_class.clear(); | 582 match->description_class.clear(); |
| 597 } | 583 } |
| 598 | 584 |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 629 } | 615 } |
| 630 | 616 |
| 631 void KeywordProvider::MaybeEndExtensionKeywordMode() { | 617 void KeywordProvider::MaybeEndExtensionKeywordMode() { |
| 632 if (!current_keyword_extension_id_.empty()) { | 618 if (!current_keyword_extension_id_.empty()) { |
| 633 extensions::ExtensionOmniboxEventRouter::OnInputCancelled( | 619 extensions::ExtensionOmniboxEventRouter::OnInputCancelled( |
| 634 profile_, current_keyword_extension_id_); | 620 profile_, current_keyword_extension_id_); |
| 635 | 621 |
| 636 current_keyword_extension_id_.clear(); | 622 current_keyword_extension_id_.clear(); |
| 637 } | 623 } |
| 638 } | 624 } |
| OLD | NEW |