• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
3 // found in the LICENSE file.
4 
5 #ifndef CHROME_BROWSER_AUTOCOMPLETE_HISTORY_URL_PROVIDER_H_
6 #define CHROME_BROWSER_AUTOCOMPLETE_HISTORY_URL_PROVIDER_H_
7 
8 #include <string>
9 #include <vector>
10 
11 #include "base/compiler_specific.h"
12 #include "base/synchronization/cancellation_flag.h"
13 #include "chrome/browser/autocomplete/autocomplete_input.h"
14 #include "chrome/browser/autocomplete/history_provider.h"
15 #include "chrome/browser/autocomplete/history_provider_util.h"
16 #include "chrome/browser/omnibox/omnibox_field_trial.h"
17 #include "chrome/browser/search_engines/template_url.h"
18 
19 class Profile;
20 class SearchTermsData;
21 
22 namespace base {
23 class MessageLoop;
24 }
25 
26 namespace history {
27 class HistoryBackend;
28 class URLDatabase;
29 }
30 
31 // How history autocomplete works
32 // ==============================
33 //
34 // Read down this diagram for temporal ordering.
35 //
36 //   Main thread                History thread
37 //   -----------                --------------
38 //   AutocompleteController::Start
39 //     -> HistoryURLProvider::Start
40 //       -> SuggestExactInput
41 //       [params_ allocated]
42 //       -> DoAutocomplete (for inline autocomplete)
43 //         -> URLDatabase::AutocompleteForPrefix (on in-memory DB)
44 //       -> HistoryService::ScheduleAutocomplete
45 //       (return to controller) ----
46 //                                 /
47 //                            HistoryBackend::ScheduleAutocomplete
48 //                              -> HistoryURLProvider::ExecuteWithDB
49 //                                -> DoAutocomplete
50 //                                  -> URLDatabase::AutocompleteForPrefix
51 //                              /
52 //   HistoryService::QueryComplete
53 //     [params_ destroyed]
54 //     -> AutocompleteProviderListener::OnProviderUpdate
55 //
56 // The autocomplete controller calls us, and must be called back, on the main
57 // thread.  When called, we run two autocomplete passes.  The first pass runs
58 // synchronously on the main thread and queries the in-memory URL database.
59 // This pass promotes matches for inline autocomplete if applicable.  We do
60 // this synchronously so that users get consistent behavior when they type
61 // quickly and hit enter, no matter how loaded the main history database is.
62 // Doing this synchronously also prevents inline autocomplete from being
63 // "flickery" in the AutocompleteEdit.  Because the in-memory DB does not have
64 // redirect data, results other than the top match might change between the
65 // two passes, so we can't just decide to use this pass' matches as the final
66 // results.
67 //
68 // The second autocomplete pass uses the full history database, which must be
69 // queried on the history thread.  Start() asks the history service schedule to
70 // callback on the history thread with a pointer to the main database.  When we
71 // are done doing queries, we schedule a task on the main thread that notifies
72 // the AutocompleteController that we're done.
73 //
74 // The communication between these threads is done using a
75 // HistoryURLProviderParams object.  This is allocated in the main thread, and
76 // normally deleted in QueryComplete().  So that both autocomplete passes can
77 // use the same code, we also use this to hold results during the first
78 // autocomplete pass.
79 //
80 // While the second pass is running, the AutocompleteController may cancel the
81 // request.  This can happen frequently when the user is typing quickly.  In
82 // this case, the main thread sets params_->cancel, which the background thread
83 // checks periodically.  If it finds the flag set, it stops what it's doing
84 // immediately and calls back to the main thread.  (We don't delete the params
85 // on the history thread, because we should only do that when we can safely
86 // NULL out params_, and that must be done on the main thread.)
87 
88 // Used to communicate autocomplete parameters between threads via the history
89 // service.
90 struct HistoryURLProviderParams {
91   // See comments on |promote_type| below.
92   enum PromoteType {
93     WHAT_YOU_TYPED_MATCH,
94     FRONT_HISTORY_MATCH,
95     NEITHER,
96   };
97 
98   HistoryURLProviderParams(const AutocompleteInput& input,
99                            bool trim_http,
100                            const AutocompleteMatch& what_you_typed_match,
101                            const std::string& languages,
102                            TemplateURL* default_search_provider,
103                            const SearchTermsData& search_terms_data);
104   ~HistoryURLProviderParams();
105 
106   base::MessageLoop* message_loop;
107 
108   // A copy of the autocomplete input. We need the copy since this object will
109   // live beyond the original query while it runs on the history thread.
110   AutocompleteInput input;
111 
112   // Should inline autocompletion be disabled? This is initalized from
113   // |input.prevent_inline_autocomplete()|, but set to false is the input
114   // contains trailing white space.
115   bool prevent_inline_autocomplete;
116 
117   // Set when "http://" should be trimmed from the beginning of the URLs.
118   bool trim_http;
119 
120   // A match corresponding to what the user typed.
121   AutocompleteMatch what_you_typed_match;
122 
123   // Set by the main thread to cancel this request.  If this flag is set when
124   // the query runs, the query will be abandoned.  This allows us to avoid
125   // running queries that are no longer needed.  Since we don't care if we run
126   // the extra queries, the lack of signaling is not a problem.
127   base::CancellationFlag cancel_flag;
128 
129   // Set by ExecuteWithDB() on the history thread when the query could not be
130   // performed because the history system failed to properly init the database.
131   // If this is set when the main thread is called back, it avoids changing
132   // |matches_| at all, so it won't delete the default match Start() creates.
133   bool failed;
134 
135   // List of matches written by DoAutocomplete().  Upon its return the provider
136   // converts this list to ACMatches and places them in |matches_|.
137   history::HistoryMatches matches;
138 
139   // True if the suggestion for exactly what the user typed appears as a known
140   // URL in the user's history.  In this case, this will also be the first match
141   // in |matches|.
142   //
143   // NOTE: There are some complications related to keeping things consistent
144   // between passes and how we deal with intranet URLs, which are too complex to
145   // explain here; see the implementations of DoAutocomplete() and
146   // FixupExactSuggestion() for specific comments.
147   bool exact_suggestion_is_in_history;
148 
149   // Tells the provider whether to promote the what you typed match, the first
150   // element of |matches|, or neither as the first AutocompleteMatch.  If
151   // |exact_suggestion_is_in_history| is true (and thus "the what you typed
152   // match" and "the first element of |matches|" represent the same thing), this
153   // will be set to WHAT_YOU_TYPED_MATCH.
154   //
155   // NOTE: The second pass of DoAutocomplete() checks what the first pass set
156   // this to.  See comments in DoAutocomplete().
157   PromoteType promote_type;
158 
159   // True if we should consider adding the what you typed match.  This
160   // decision is often already summarized in |promote_type| by whether it
161   // says to promote the what you typed match.  As such, this variable is
162   // only useful when |promote_type| is FRONT_HISTORY_MATCH.
163   bool have_what_you_typed_match;
164 
165   // Languages we should pass to gfx::GetCleanStringFromUrl.
166   std::string languages;
167 
168   // The default search provider and search terms data necessary to cull results
169   // that correspond to searches (on the default engine).  These can only be
170   // obtained on the UI thread, so we have to copy them into here to pass them
171   // to the history thread.  We use a scoped_ptr<TemplateURL> for the DSP since
172   // TemplateURLs can't be copied by value. We use a scoped_ptr<SearchTermsData>
173   // so that we can store a snapshot of the SearchTermsData accessible from the
174   // history thread.
175   scoped_ptr<TemplateURL> default_search_provider;
176   scoped_ptr<SearchTermsData> search_terms_data;
177 
178  private:
179   DISALLOW_COPY_AND_ASSIGN(HistoryURLProviderParams);
180 };
181 
182 // This class is an autocomplete provider and is also a pseudo-internal
183 // component of the history system.  See comments above.
184 class HistoryURLProvider : public HistoryProvider {
185  public:
186   // Various values used in scoring, made public so other providers
187   // can insert results in appropriate ranges relative to these.
188   static const int kScoreForBestInlineableResult;
189   static const int kScoreForUnvisitedIntranetResult;
190   static const int kScoreForWhatYouTypedResult;
191   static const int kBaseScoreForNonInlineableResult;
192 
193   HistoryURLProvider(AutocompleteProviderListener* listener, Profile* profile);
194 
195   // HistoryProvider:
196   virtual void Start(const AutocompleteInput& input,
197                      bool minimal_changes) OVERRIDE;
198   virtual void Stop(bool clear_cached_results) OVERRIDE;
199 
200   // Returns a match representing a navigation to |destination_url| given user
201   // input of |text|.  |trim_http| controls whether the match's |fill_into_edit|
202   // and |contents| should have any HTTP scheme stripped off, and should not be
203   // set to true if |text| contains an http prefix.
204   // NOTES: This does not set the relevance of the returned match, as different
205   //        callers want different behavior. Callers must set this manually.
206   //        This function should only be called on the UI thread.
207   AutocompleteMatch SuggestExactInput(const base::string16& text,
208                                       const GURL& destination_url,
209                                       bool trim_http);
210 
211   // Runs the history query on the history thread, called by the history
212   // system. The history database MAY BE NULL in which case it is not
213   // available and we should return no data. Also schedules returning the
214   // results to the main thread
215   void ExecuteWithDB(history::HistoryBackend* backend,
216                      history::URLDatabase* db,
217                      HistoryURLProviderParams* params);
218 
219  private:
220   FRIEND_TEST_ALL_PREFIXES(HistoryURLProviderTest, HUPScoringExperiment);
221 
222   enum MatchType {
223     NORMAL,
224     WHAT_YOU_TYPED,
225     INLINE_AUTOCOMPLETE,
226     UNVISITED_INTRANET,  // An intranet site that has never been visited.
227   };
228   class VisitClassifier;
229 
230   ~HistoryURLProvider();
231 
232   // Determines the relevance for a match, given its type.  If |match_type| is
233   // NORMAL, |match_number| is a number indicating the relevance of the match
234   // (higher == more relevant).  For other values of |match_type|,
235   // |match_number| is ignored.  Only called some of the time; for some matches,
236   // relevancy scores are assigned consecutively decreasing (1416, 1415, ...).
237   static int CalculateRelevance(MatchType match_type, int match_number);
238 
239   // Returns a set of classifications that highlight all the occurrences of
240   // |input_text| at word breaks in |description|.
241   static ACMatchClassifications ClassifyDescription(
242       const base::string16& input_text,
243       const base::string16& description);
244 
245   // Actually runs the autocomplete job on the given database, which is
246   // guaranteed not to be NULL.  Used by both autocomplete passes, and therefore
247   // called on multiple different threads (though not simultaneously).
248   void DoAutocomplete(history::HistoryBackend* backend,
249                       history::URLDatabase* db,
250                       HistoryURLProviderParams* params);
251 
252   // May promote either the what you typed match or first history match in
253   // params->matches to the front of |matches_|, depending on the value of
254   // params->promote_type.  Also, depending on a field trial state, if it
255   // promotes the first history match, it may decide to append the what you
256   // typed matche immediately after.
257   void PromoteMatchesIfNecessary(const HistoryURLProviderParams& params);
258 
259   // Dispatches the results to the autocomplete controller. Called on the
260   // main thread by ExecuteWithDB when the results are available.
261   // Frees params_gets_deleted on exit.
262   void QueryComplete(HistoryURLProviderParams* params_gets_deleted);
263 
264   // Looks up the info for params->what_you_typed_match in the DB.  If found,
265   // fills in the title, promotes the match's priority to that of an inline
266   // autocomplete match (maybe it should be slightly better?), and places it on
267   // the front of params->matches (so we pick the right matches to throw away
268   // when culling redirects to/from it).  Returns whether a match was promoted.
269   bool FixupExactSuggestion(history::URLDatabase* db,
270                             const VisitClassifier& classifier,
271                             HistoryURLProviderParams* params) const;
272 
273   // Helper function for FixupExactSuggestion, this returns true if the input
274   // corresponds to some intranet URL where the user has previously visited the
275   // host in question.  In this case the input should be treated as a URL.
276   bool CanFindIntranetURL(history::URLDatabase* db,
277                           const AutocompleteInput& input) const;
278 
279   // Sees if a shorter version of the best match should be created, and if so
280   // places it at the front of params->matches.  This can suggest history URLs
281   // that are prefixes of the best match (if they've been visited enough,
282   // compared to the best match), or create host-only suggestions even when they
283   // haven't been visited before: if the user visited http://example.com/asdf
284   // once, we'll suggest http://example.com/ even if they've never been to it.
285   // Returns true if a match was successfully created/promoted that we're
286   // willing to inline autocomplete.
287   bool PromoteOrCreateShorterSuggestion(
288       history::URLDatabase* db,
289       bool have_what_you_typed_match,
290       HistoryURLProviderParams* params);
291 
292   // Removes results that have been rarely typed or visited, and not any time
293   // recently.  The exact parameters for this heuristic can be found in the
294   // function body. Also culls results corresponding to queries from the default
295   // search engine. These are low-quality, difficult-to-understand matches for
296   // users, and the SearchProvider should surface past queries in a better way
297   // anyway.
298   void CullPoorMatches(HistoryURLProviderParams* params) const;
299 
300   // Removes results that redirect to each other, leaving at most |max_results|
301   // results.
302   void CullRedirects(history::HistoryBackend* backend,
303                      history::HistoryMatches* matches,
304                      size_t max_results) const;
305 
306   // Helper function for CullRedirects, this removes all but the first
307   // occurance of [any of the set of strings in |remove|] from the |matches|
308   // list.
309   //
310   // The return value is the index of the item that is after the item in the
311   // input identified by |source_index|. If |source_index| or an item before
312   // is removed, the next item will be shifted, and this allows the caller to
313   // pick up on the next one when this happens.
314   size_t RemoveSubsequentMatchesOf(history::HistoryMatches* matches,
315                                    size_t source_index,
316                                    const std::vector<GURL>& remove) const;
317 
318   // Converts a specified |match_number| from params.matches into an
319   // autocomplete match for display.  If experimental scoring is enabled, the
320   // final relevance score might be different from the given |relevance|.
321   // NOTE: This function should only be called on the UI thread.
322   AutocompleteMatch HistoryMatchToACMatch(
323       const HistoryURLProviderParams& params,
324       size_t match_number,
325       MatchType match_type,
326       int relevance);
327 
328   // Params for the current query.  The provider should not free this directly;
329   // instead, it is passed as a parameter through the history backend, and the
330   // parameter itself is freed once it's no longer needed.  The only reason we
331   // keep this member is so we can set the cancel bit on it.
332   HistoryURLProviderParams* params_;
333 
334   // Params controlling experimental behavior of this provider.
335   HUPScoringParams scoring_params_;
336 
337   // If true, HistoryURL provider should lookup and cull redirects.  If
338   // false, it returns matches that may be redirects to each other and
339   // simply hopes the default AutoCompleteController behavior to remove
340   // URLs that are likely duplicates (http://google.com <->
341   // https://www.google.com/, etc.) will do a good enough job.
342   bool cull_redirects_;
343 
344   // Used in PromoteOrCreateShorterSuggestion().  If true, we may create
345   // shorter suggestions even when they haven't been visited before:
346   // if the user visited http://example.com/asdf once, we'll suggest
347   // http://example.com/ even if they've never been to it.
348   bool create_shorter_match_;
349 
350   DISALLOW_COPY_AND_ASSIGN(HistoryURLProvider);
351 };
352 
353 #endif  // CHROME_BROWSER_AUTOCOMPLETE_HISTORY_URL_PROVIDER_H_
354