// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // // This file contains the Search autocomplete provider. This provider is // responsible for all non-keyword autocomplete entries that start with // "Search for ...", including searching for the current input string, // search history, and search suggestions. An instance of it gets created and // managed by the autocomplete controller. // // For more information on the autocomplete system in general, including how // the autocomplete controller and autocomplete providers work, see // chrome/browser/autocomplete.h. #ifndef CHROME_BROWSER_AUTOCOMPLETE_SEARCH_PROVIDER_H_ #define CHROME_BROWSER_AUTOCOMPLETE_SEARCH_PROVIDER_H_ #pragma once #include #include #include #include "base/memory/scoped_ptr.h" #include "base/time.h" #include "chrome/browser/autocomplete/autocomplete.h" #include "chrome/browser/autocomplete/autocomplete_match.h" #include "chrome/browser/autocomplete/autocomplete_provider.h" #include "chrome/browser/history/history_types.h" #include "chrome/browser/search_engines/template_url.h" #include "chrome/browser/search_engines/template_url_id.h" #include "net/url_request/url_fetcher_delegate.h" class Profile; class TemplateURLService; namespace base { class Value; } namespace net { class URLFetcher; } // Autocomplete provider for searches and suggestions from a search engine. // // After construction, the autocomplete controller repeatedly calls Start() // with some user input, each time expecting to receive a small set of the best // matches (either synchronously or asynchronously). // // Initially the provider creates a match that searches for the current input // text. It also starts a task to query the Suggest servers. When that data // comes back, the provider creates and returns matches for the best // suggestions. class SearchProvider : public AutocompleteProvider, public net::URLFetcherDelegate { public: SearchProvider(AutocompleteProviderListener* listener, Profile* profile); #if defined(UNIT_TEST) static void set_query_suggest_immediately(bool value) { query_suggest_immediately_ = value; } #endif // Marks the instant query as done. If |input_text| is non-empty this changes // the 'search what you typed' results text to |input_text| + |suggest_text|. // |input_text| is the text the user input into the edit. |input_text| differs // from |input_.text()| if the input contained whitespace. // // This method also marks the search provider as no longer needing to wait for // the instant result. void FinalizeInstantQuery(const string16& input_text, const string16& suggest_text); // AutocompleteProvider virtual void Start(const AutocompleteInput& input, bool minimal_changes) OVERRIDE; virtual void Stop() OVERRIDE; // Adds search-provider-specific information to omnibox event logs. virtual void AddProviderInfo(ProvidersInfo* provider_info) const OVERRIDE; // net::URLFetcherDelegate virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE; // ID used in creating URLFetcher for default provider's suggest results. static const int kDefaultProviderURLFetcherID; // ID used in creating URLFetcher for keyword provider's suggest results. static const int kKeywordProviderURLFetcherID; private: FRIEND_TEST_ALL_PREFIXES(SearchProviderTest, SuggestRelevanceExperiment); FRIEND_TEST_ALL_PREFIXES(SearchProviderTest, NavigationInline); FRIEND_TEST_ALL_PREFIXES(SearchProviderTest, NavigationInlineSchemeSubstring); FRIEND_TEST_ALL_PREFIXES(SearchProviderTest, NavigationInlineDomainClassify); virtual ~SearchProvider(); // Manages the providers (TemplateURLs) used by SearchProvider. Two providers // may be used: // . The default provider. This corresponds to the user's default search // engine. This is always used, except for the rare case of no default // engine. // . The keyword provider. This is used if the user has typed in a keyword. class Providers { public: explicit Providers(TemplateURLService* template_url_service); // Returns true if the specified providers match the two providers cached // by this class. bool equal(const string16& default_provider, const string16& keyword_provider) const { return (default_provider == default_provider_) && (keyword_provider == keyword_provider_); } // Resets the cached providers. void set(const string16& default_provider, const string16& keyword_provider) { default_provider_ = default_provider; keyword_provider_ = keyword_provider; } TemplateURLService* template_url_service() { return template_url_service_; } const string16& default_provider() const { return default_provider_; } const string16& keyword_provider() const { return keyword_provider_; } // NOTE: These may return NULL even if the provider members are nonempty! const TemplateURL* GetDefaultProviderURL() const; const TemplateURL* GetKeywordProviderURL() const; // Returns true if |from_keyword_provider| is true, or the keyword provider // is not valid. bool is_primary_provider(bool from_keyword_provider) const { return from_keyword_provider || keyword_provider_.empty(); } private: TemplateURLService* template_url_service_; // Cached across the life of a query so we behave consistently even if the // user changes their default while the query is running. string16 default_provider_; string16 keyword_provider_; DISALLOW_COPY_AND_ASSIGN(Providers); }; // The Result classes are intermediate representations of AutocompleteMatches, // simply containing relevance-ranked search and navigation suggestions. // They may be cached to provide some synchronous matches while requests for // new suggestions from updated input are in flight. // TODO(msw) Extend these classes to generate their corresponding matches and // other requisite data, in order to consolidate and simplify the // highly fragmented SearchProvider logic for each Result type. class Result { public: explicit Result(int relevance); virtual ~Result(); int relevance() const { return relevance_; } void set_relevance(int relevance) { relevance_ = relevance; } private: // The relevance score. int relevance_; }; class SuggestResult : public Result { public: SuggestResult(const string16& suggestion, int relevance); virtual ~SuggestResult(); const string16& suggestion() const { return suggestion_; } private: // The search suggestion string. string16 suggestion_; }; class NavigationResult : public Result { public: NavigationResult(const GURL& url, const string16& description, int relevance); virtual ~NavigationResult(); const GURL& url() const { return url_; } const string16& description() const { return description_; } private: // The suggested url for navigation. GURL url_; // The suggested navigational result description; generally the site name. string16 description_; }; typedef std::vector SuggestResults; typedef std::vector NavigationResults; typedef std::vector HistoryResults; typedef std::map MatchMap; class CompareScoredResults; // Called when timer_ expires. void Run(); // Runs the history query, if necessary. The history query is synchronous. // This does not update |done_|. void DoHistoryQuery(bool minimal_changes); // Determines whether an asynchronous subcomponent query should run for the // current input. If so, starts it if necessary; otherwise stops it. // NOTE: This function does not update |done_|. Callers must do so. void StartOrStopSuggestQuery(bool minimal_changes); // Returns true when the current query can be sent to the Suggest service. // This will be false e.g. when Suggest is disabled, the query contains // potentially private data, etc. bool IsQuerySuitableForSuggest() const; // Stops the suggest query. // NOTE: This does not update |done_|. Callers must do so. void StopSuggest(); // Clears the current results. void ClearResults(); // Remove results that cannot inline auto-complete the current input. void RemoveStaleResults(); void RemoveStaleSuggestResults(SuggestResults* list, bool is_keyword); void RemoveStaleNavigationResults(NavigationResults* list, bool is_keyword); // Apply calculated relevance scores to the current results. void ApplyCalculatedRelevance(); void ApplyCalculatedSuggestRelevance(SuggestResults* list, bool is_keyword); void ApplyCalculatedNavigationRelevance(NavigationResults* list, bool is_keyword); // Creates a URLFetcher requesting suggest results from the specified // |suggestions_url|. The caller owns the returned URLFetcher. net::URLFetcher* CreateSuggestFetcher( int id, const TemplateURLRef& suggestions_url, const string16& text); // Parses results from the suggest server and updates the appropriate suggest // and navigation result lists, depending on whether |is_keyword| is true. // Returns whether the appropriate result list members were updated. bool ParseSuggestResults(base::Value* root_val, bool is_keyword); // Converts the parsed results to a set of AutocompleteMatches and adds them // to |matches_|. This also sets |done_| correctly. void ConvertResultsToAutocompleteMatches(); // Converts the first navigation result in |navigation_results| to an // AutocompleteMatch and adds it to |matches_|. void AddNavigationResultsToMatches( const NavigationResults& navigation_results, bool is_keyword); // Adds a match for each result in |results| to |map|. |is_keyword| indicates // whether the results correspond to the keyword provider or default provider. void AddHistoryResultsToMap(const HistoryResults& results, bool is_keyword, int did_not_accept_suggestion, MatchMap* map); // Calculates relevance scores for all |results|. SuggestResults ScoreHistoryResults(const HistoryResults& results, bool base_prevent_inline_autocomplete, bool input_multiple_words, const string16& input_text, bool is_keyword); // Adds matches for |results| to |map|. |is_keyword| indicates whether the // results correspond to the keyword provider or default provider. void AddSuggestResultsToMap(const SuggestResults& results, bool is_keyword, MatchMap* map); // Get the relevance score for the verbatim result; this value may be provided // by the suggest server; otherwise it is calculated locally. int GetVerbatimRelevance() const; // Calculate the relevance score for the verbatim result. int CalculateRelevanceForVerbatim() const; // |time| is the time at which this query was last seen. |is_keyword| // indicates whether the results correspond to the keyword provider or default // provider. |prevent_inline_autocomplete| is true if we should not inline // autocomplete this query. int CalculateRelevanceForHistory(const base::Time& time, bool is_keyword, bool prevent_inline_autocomplete) const; // Calculate the relevance for search suggestion results. Set |for_keyword| to // true for relevance values applicable to keyword provider results. int CalculateRelevanceForSuggestion(bool for_keyword) const; // Calculate the relevance for navigation results. Set |for_keyword| to true // for relevance values applicable to keyword provider results. int CalculateRelevanceForNavigation(bool for_keyword) const; // Creates an AutocompleteMatch for "Search for |query_string|" with // the supplied relevance. Adds this match to |map|; if such a match already // exists, whichever one has lower relevance is eliminated. void AddMatchToMap(const string16& query_string, const string16& input_text, int relevance, AutocompleteMatch::Type type, int accepted_suggestion, bool is_keyword, MatchMap* map); // Returns an AutocompleteMatch for a navigational suggestion. AutocompleteMatch NavigationToMatch(const NavigationResult& navigation, bool is_keyword); // Updates the value of |done_| from the internal state. void UpdateDone(); // Should we query for suggest results immediately? This is normally false, // but may be set to true during testing. static bool query_suggest_immediately_; // Maintains the TemplateURLs used. Providers providers_; // The user's input. AutocompleteInput input_; // Input text when searching against the keyword provider. string16 keyword_input_text_; // Searches in the user's history that begin with the input text. HistoryResults keyword_history_results_; HistoryResults default_history_results_; // Number of suggest results that haven't yet arrived. If greater than 0 it // indicates either |timer_| or one of the URLFetchers is still running. int suggest_results_pending_; // A timer to start a query to the suggest server after the user has stopped // typing for long enough. base::OneShotTimer timer_; // The time at which we sent a query to the suggest server. base::TimeTicks time_suggest_request_sent_; // Fetchers used to retrieve results for the keyword and default providers. scoped_ptr keyword_fetcher_; scoped_ptr default_fetcher_; // Suggestions returned by the Suggest server for the input text. SuggestResults keyword_suggest_results_; SuggestResults default_suggest_results_; // Navigational suggestions returned by the server. NavigationResults keyword_navigation_results_; NavigationResults default_navigation_results_; // A flag indicating use of server supplied relevance scores. bool has_suggested_relevance_; // The server supplied verbatim relevance score. Negative values indicate that // there is no suggested score; a value of 0 suppresses the verbatim result. int verbatim_relevance_; // Whether suggest_results_ is valid. bool have_suggest_results_; // Has FinalizeInstantQuery been invoked since the last |Start|? bool instant_finalized_; // The |suggest_text| parameter passed to FinalizeInstantQuery. string16 default_provider_suggest_text_; DISALLOW_COPY_AND_ASSIGN(SearchProvider); }; #endif // CHROME_BROWSER_AUTOCOMPLETE_SEARCH_PROVIDER_H_