• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
3 // found in the LICENSE file.
4 //
5 // This file contains the Search autocomplete provider.  This provider is
6 // responsible for all non-keyword autocomplete entries that start with
7 // "Search <engine> for ...", including searching for the current input string,
8 // search history, and search suggestions.  An instance of it gets created and
9 // managed by the autocomplete controller.
10 //
11 // For more information on the autocomplete system in general, including how
12 // the autocomplete controller and autocomplete providers work, see
13 // chrome/browser/autocomplete.h.
14 
15 #ifndef CHROME_BROWSER_AUTOCOMPLETE_SEARCH_PROVIDER_H_
16 #define CHROME_BROWSER_AUTOCOMPLETE_SEARCH_PROVIDER_H_
17 #pragma once
18 
19 #include <map>
20 #include <string>
21 #include <vector>
22 
23 #include "base/memory/scoped_ptr.h"
24 #include "chrome/browser/autocomplete/autocomplete.h"
25 #include "chrome/browser/autocomplete/autocomplete_match.h"
26 #include "chrome/browser/history/history_types.h"
27 #include "chrome/browser/search_engines/template_url.h"
28 #include "chrome/browser/search_engines/template_url_id.h"
29 #include "chrome/common/net/url_fetcher.h"
30 
31 class Profile;
32 class Value;
33 
34 // Autocomplete provider for searches and suggestions from a search engine.
35 //
36 // After construction, the autocomplete controller repeatedly calls Start()
37 // with some user input, each time expecting to receive a small set of the best
38 // matches (either synchronously or asynchronously).
39 //
40 // Initially the provider creates a match that searches for the current input
41 // text.  It also starts a task to query the Suggest servers.  When that data
42 // comes back, the provider creates and returns matches for the best
43 // suggestions.
44 class SearchProvider : public AutocompleteProvider,
45                        public URLFetcher::Delegate {
46  public:
47   SearchProvider(ACProviderListener* listener, Profile* profile);
48 
49 #if defined(UNIT_TEST)
set_query_suggest_immediately(bool value)50   static void set_query_suggest_immediately(bool value) {
51     query_suggest_immediately_ = value;
52   }
53 #endif
54 
55   // Marks the instant query as done. If |input_text| is non-empty this changes
56   // the 'search what you typed' results text to |input_text| + |suggest_text|.
57   // |input_text| is the text the user input into the edit. |input_text| differs
58   // from |input_.text()| if the input contained whitespace.
59   //
60   // This method also marks the search provider as no longer needing to wait for
61   // the instant result.
62   void FinalizeInstantQuery(const string16& input_text,
63                             const string16& suggest_text);
64 
65   // AutocompleteProvider
66   virtual void Start(const AutocompleteInput& input,
67                      bool minimal_changes);
68   virtual void Stop();
69 
70   // URLFetcher::Delegate
71   virtual void OnURLFetchComplete(const URLFetcher* source,
72                                   const GURL& url,
73                                   const net::URLRequestStatus& status,
74                                   int response_code,
75                                   const ResponseCookies& cookies,
76                                   const std::string& data);
77 
78   // ID used in creating URLFetcher for default provider's suggest results.
79   static const int kDefaultProviderURLFetcherID;
80 
81   // ID used in creating URLFetcher for keyword provider's suggest results.
82   static const int kKeywordProviderURLFetcherID;
83 
84  private:
85   ~SearchProvider();
86 
87   // Manages the providers (TemplateURLs) used by SearchProvider. Two providers
88   // may be used:
89   // . The default provider. This corresponds to the user's default search
90   //   engine. This is always used, except for the rare case of no default
91   //   engine.
92   // . The keyword provider. This is used if the user has typed in a keyword.
93   class Providers {
94    public:
Providers()95     Providers() : default_provider_(NULL), keyword_provider_(NULL) {}
96 
97     // Returns true if the specified providers match the two providers managed
98     // by this class.
equals(const TemplateURL * default_provider,const TemplateURL * keyword_provider)99     bool equals(const TemplateURL* default_provider,
100                 const TemplateURL* keyword_provider) {
101       return (default_provider == default_provider_ &&
102               keyword_provider == keyword_provider_);
103     }
104 
105     // Resets the providers.
106     void Set(const TemplateURL* default_provider,
107              const TemplateURL* keyword_provider);
108 
default_provider()109     const TemplateURL& default_provider() const {
110       DCHECK(valid_default_provider());
111       return cached_default_provider_;
112     }
113 
keyword_provider()114     const TemplateURL& keyword_provider() const {
115       DCHECK(valid_keyword_provider());
116       return cached_keyword_provider_;
117     }
118 
119     // Returns true of the keyword provider is valid.
valid_keyword_provider()120     bool valid_keyword_provider() const { return !!keyword_provider_; }
121 
122     // Returns true if the keyword provider is valid and has a valid suggest
123     // url.
valid_suggest_for_keyword_provider()124     bool valid_suggest_for_keyword_provider() const {
125       return keyword_provider_ && cached_keyword_provider_.suggestions_url();
126     }
127 
128     // Returns true of the default provider is valid.
valid_default_provider()129     bool valid_default_provider() const { return !!default_provider_; }
130 
131     // Returns true if the default provider is valid and has a valid suggest
132     // url.
valid_suggest_for_default_provider()133     bool valid_suggest_for_default_provider() const {
134       return default_provider_ && cached_default_provider_.suggestions_url();
135     }
136 
137     // Returns true if |from_keyword_provider| is true, or
138     // the keyword provider is not valid.
is_primary_provider(bool from_keyword_provider)139     bool is_primary_provider(bool from_keyword_provider) const {
140       return from_keyword_provider || !valid_keyword_provider();
141     }
142 
143    private:
144     // Cached across the life of a query so we behave consistently even if the
145     // user changes their default while the query is running.
146     TemplateURL cached_default_provider_;
147     TemplateURL cached_keyword_provider_;
148 
149     // TODO(pkasting): http://b/1162970  We shouldn't need these.
150     const TemplateURL* default_provider_;
151     const TemplateURL* keyword_provider_;
152   };
153 
154   struct NavigationResult {
NavigationResultNavigationResult155     NavigationResult(const GURL& url, const string16& site_name)
156         : url(url),
157           site_name(site_name) {
158     }
159 
160     // The URL.
161     GURL url;
162 
163     // Name for the site.
164     string16 site_name;
165   };
166 
167   typedef std::vector<string16> SuggestResults;
168   typedef std::vector<NavigationResult> NavigationResults;
169   typedef std::vector<history::KeywordSearchTermVisit> HistoryResults;
170   typedef std::map<string16, AutocompleteMatch> MatchMap;
171 
172   // Called when timer_ expires.
173   void Run();
174 
175   // Runs the history query, if necessary. The history query is synchronous.
176   // This does not update |done_|.
177   void DoHistoryQuery(bool minimal_changes);
178 
179   // Determines whether an asynchronous subcomponent query should run for the
180   // current input.  If so, starts it if necessary; otherwise stops it.
181   // NOTE: This function does not update |done_|.  Callers must do so.
182   void StartOrStopSuggestQuery(bool minimal_changes);
183 
184   // Returns true when the current query can be sent to the Suggest service.
185   // This will be false e.g. when Suggest is disabled, the query contains
186   // potentially private data, etc.
187   bool IsQuerySuitableForSuggest() const;
188 
189   // Stops the suggest query.
190   // NOTE: This does not update |done_|.  Callers must do so.
191   void StopSuggest();
192 
193   // Creates a URLFetcher requesting suggest results for the specified
194   // TemplateURL. Ownership of the returned URLFetchet passes to the caller.
195   URLFetcher* CreateSuggestFetcher(int id,
196                                    const TemplateURL& provider,
197                                    const string16& text);
198 
199   // Parses the results from the Suggest server and stores up to kMaxMatches of
200   // them in server_results_.  Returns whether parsing succeeded.
201   bool ParseSuggestResults(Value* root_val,
202                            bool is_keyword,
203                            const string16& input_text,
204                            SuggestResults* suggest_results);
205 
206   // Converts the parsed server results in server_results_ to a set of
207   // AutocompleteMatches and adds them to |matches_|.  This also sets |done_|
208   // correctly.
209   void ConvertResultsToAutocompleteMatches();
210 
211   // Converts the first navigation result in |navigation_results| to an
212   // AutocompleteMatch and adds it to |matches_|.
213   void AddNavigationResultsToMatches(
214     const NavigationResults& navigation_results,
215     bool is_keyword);
216 
217   // Adds a match for each result in |results| to |map|. |is_keyword| indicates
218   // whether the results correspond to the keyword provider or default provider.
219   void AddHistoryResultsToMap(const HistoryResults& results,
220                               bool is_keyword,
221                               int did_not_accept_suggestion,
222                               MatchMap* map);
223 
224   // Adds a match for each result in |suggest_results| to |map|. |is_keyword|
225   // indicates whether the results correspond to the keyword provider or default
226   // provider.
227   void AddSuggestResultsToMap(const SuggestResults& suggest_results,
228                               bool is_keyword,
229                               int did_not_accept_suggestion,
230                               MatchMap* map);
231 
232   // Determines the relevance for a particular match.  We use different scoring
233   // algorithms for the different types of matches.
234   int CalculateRelevanceForWhatYouTyped() const;
235   // |time| is the time at which this query was last seen. |is_keyword| is true
236   // if the search is from the keyword provider. |looks_like_url| is true if the
237   // search term would be treated as a URL if typed into the omnibox.
238   int CalculateRelevanceForHistory(const base::Time& time,
239                                    bool looks_like_url,
240                                    bool is_keyword) const;
241   // |result_number| is the index of the suggestion in the result set from the
242   // server; the best suggestion is suggestion number 0.  |is_keyword| is true
243   // if the search is from the keyword provider.
244   int CalculateRelevanceForSuggestion(size_t num_results,
245                                       size_t result_number,
246                                       bool is_keyword) const;
247   // |result_number| is same as above. |is_keyword| is true if the navigation
248   // result was suggested by the keyword provider.
249   int CalculateRelevanceForNavigation(size_t num_results,
250                                       size_t result_number,
251                                       bool is_keyword) const;
252 
253   // Creates an AutocompleteMatch for "Search <engine> for |query_string|" with
254   // the supplied relevance.  Adds this match to |map|; if such a match already
255   // exists, whichever one has lower relevance is eliminated.
256   void AddMatchToMap(const string16& query_string,
257                      const string16& input_text,
258                      int relevance,
259                      AutocompleteMatch::Type type,
260                      int accepted_suggestion,
261                      bool is_keyword,
262                      bool prevent_inline_autocomplete,
263                      MatchMap* map);
264 
265   // Returns an AutocompleteMatch for a navigational suggestion.
266   AutocompleteMatch NavigationToMatch(const NavigationResult& query_string,
267                                       int relevance,
268                                       bool is_keyword);
269 
270   // Updates the value of |done_| from the internal state.
271   void UpdateDone();
272 
273   // Updates the description/description_class of the first search match.
274   void UpdateFirstSearchMatchDescription();
275 
276   // Should we query for suggest results immediately? This is normally false,
277   // but may be set to true during testing.
278   static bool query_suggest_immediately_;
279 
280   // Maintains the TemplateURLs used.
281   Providers providers_;
282 
283   // The user's input.
284   AutocompleteInput input_;
285 
286   // Input text when searching against the keyword provider.
287   string16 keyword_input_text_;
288 
289   // Searches in the user's history that begin with the input text.
290   HistoryResults keyword_history_results_;
291   HistoryResults default_history_results_;
292 
293   // Number of suggest results that haven't yet arrived. If greater than 0 it
294   // indicates either |timer_| or one of the URLFetchers is still running.
295   int suggest_results_pending_;
296 
297   // A timer to start a query to the suggest server after the user has stopped
298   // typing for long enough.
299   base::OneShotTimer<SearchProvider> timer_;
300 
301   // The fetcher that retrieves suggest results for the keyword from the server.
302   scoped_ptr<URLFetcher> keyword_fetcher_;
303 
304   // The fetcher that retrieves suggest results for the default engine from the
305   // server.
306   scoped_ptr<URLFetcher> default_fetcher_;
307 
308   // Suggestions returned by the Suggest server for the input text.
309   SuggestResults keyword_suggest_results_;
310   SuggestResults default_suggest_results_;
311 
312   // Navigational suggestions returned by the server.
313   NavigationResults keyword_navigation_results_;
314   NavigationResults default_navigation_results_;
315 
316   // Whether suggest_results_ is valid.
317   bool have_suggest_results_;
318 
319   // Has FinalizeInstantQuery been invoked since the last |Start|?
320   bool instant_finalized_;
321 
322   // The |suggest_text| parameter passed to FinalizeInstantQuery.
323   string16 default_provider_suggest_text_;
324 
325   DISALLOW_COPY_AND_ASSIGN(SearchProvider);
326 };
327 
328 #endif  // CHROME_BROWSER_AUTOCOMPLETE_SEARCH_PROVIDER_H_
329