Index: chrome/browser/autocomplete/history_url_provider.h |
diff --git a/chrome/browser/autocomplete/history_url_provider.h b/chrome/browser/autocomplete/history_url_provider.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..53796f45f3bb6c759eb5cac84fdb0023fb40eaaa |
--- /dev/null |
+++ b/chrome/browser/autocomplete/history_url_provider.h |
@@ -0,0 +1,344 @@ |
+// 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. |
+ |
+#ifndef CHROME_BROWSER_AUTOCOMPLETE_HISTORY_URL_PROVIDER_H_ |
+#define CHROME_BROWSER_AUTOCOMPLETE_HISTORY_URL_PROVIDER_H_ |
+ |
+#include <string> |
+#include <vector> |
+ |
+#include "base/compiler_specific.h" |
+#include "base/synchronization/cancellation_flag.h" |
+#include "base/threading/thread_checker.h" |
+#include "components/history/core/browser/history_match.h" |
+#include "components/omnibox/autocomplete_input.h" |
+#include "components/omnibox/history_provider.h" |
+#include "components/omnibox/omnibox_field_trial.h" |
+#include "components/search_engines/template_url.h" |
+ |
+class AutocompleteProviderListener; |
+class SearchTermsData; |
+ |
+namespace base { |
+class MessageLoop; |
+} |
+ |
+namespace history { |
+class HistoryBackend; |
+class URLDatabase; |
+} |
+ |
+// How history autocomplete works |
+// ============================== |
+// |
+// Read down this diagram for temporal ordering. |
+// |
+// Main thread History thread |
+// ----------- -------------- |
+// AutocompleteController::Start |
+// -> HistoryURLProvider::Start |
+// -> SuggestExactInput |
+// [params_ allocated] |
+// -> DoAutocomplete (for inline autocomplete) |
+// -> URLDatabase::AutocompleteForPrefix (on in-memory DB) |
+// -> HistoryService::ScheduleAutocomplete |
+// (return to controller) ---- |
+// / |
+// HistoryBackend::ScheduleAutocomplete |
+// -> HistoryURLProvider::ExecuteWithDB |
+// -> DoAutocomplete |
+// -> URLDatabase::AutocompleteForPrefix |
+// / |
+// HistoryService::QueryComplete |
+// [params_ destroyed] |
+// -> AutocompleteProviderListener::OnProviderUpdate |
+// |
+// The autocomplete controller calls us, and must be called back, on the main |
+// thread. When called, we run two autocomplete passes. The first pass runs |
+// synchronously on the main thread and queries the in-memory URL database. |
+// This pass promotes matches for inline autocomplete if applicable. We do |
+// this synchronously so that users get consistent behavior when they type |
+// quickly and hit enter, no matter how loaded the main history database is. |
+// Doing this synchronously also prevents inline autocomplete from being |
+// "flickery" in the AutocompleteEdit. Because the in-memory DB does not have |
+// redirect data, results other than the top match might change between the |
+// two passes, so we can't just decide to use this pass' matches as the final |
+// results. |
+// |
+// The second autocomplete pass uses the full history database, which must be |
+// queried on the history thread. Start() asks the history service schedule to |
+// callback on the history thread with a pointer to the main database. When we |
+// are done doing queries, we schedule a task on the main thread that notifies |
+// the AutocompleteController that we're done. |
+// |
+// The communication between these threads is done using a |
+// HistoryURLProviderParams object. This is allocated in the main thread, and |
+// normally deleted in QueryComplete(). So that both autocomplete passes can |
+// use the same code, we also use this to hold results during the first |
+// autocomplete pass. |
+// |
+// While the second pass is running, the AutocompleteController may cancel the |
+// request. This can happen frequently when the user is typing quickly. In |
+// this case, the main thread sets params_->cancel, which the background thread |
+// checks periodically. If it finds the flag set, it stops what it's doing |
+// immediately and calls back to the main thread. (We don't delete the params |
+// on the history thread, because we should only do that when we can safely |
+// NULL out params_, and that must be done on the main thread.) |
+ |
+// Used to communicate autocomplete parameters between threads via the history |
+// service. |
+struct HistoryURLProviderParams { |
+ // See comments on |promote_type| below. |
+ enum PromoteType { |
+ WHAT_YOU_TYPED_MATCH, |
+ FRONT_HISTORY_MATCH, |
+ NEITHER, |
+ }; |
+ |
+ HistoryURLProviderParams(const AutocompleteInput& input, |
+ bool trim_http, |
+ const AutocompleteMatch& what_you_typed_match, |
+ const std::string& languages, |
+ TemplateURL* default_search_provider, |
+ const SearchTermsData& search_terms_data); |
+ ~HistoryURLProviderParams(); |
+ |
+ base::MessageLoop* message_loop; |
+ |
+ // A copy of the autocomplete input. We need the copy since this object will |
+ // live beyond the original query while it runs on the history thread. |
+ AutocompleteInput input; |
+ |
+ // Should inline autocompletion be disabled? This is initalized from |
+ // |input.prevent_inline_autocomplete()|, but set to false is the input |
+ // contains trailing white space. |
+ bool prevent_inline_autocomplete; |
+ |
+ // Set when "http://" should be trimmed from the beginning of the URLs. |
+ bool trim_http; |
+ |
+ // A match corresponding to what the user typed. |
+ AutocompleteMatch what_you_typed_match; |
+ |
+ // Set by the main thread to cancel this request. If this flag is set when |
+ // the query runs, the query will be abandoned. This allows us to avoid |
+ // running queries that are no longer needed. Since we don't care if we run |
+ // the extra queries, the lack of signaling is not a problem. |
+ base::CancellationFlag cancel_flag; |
+ |
+ // Set by ExecuteWithDB() on the history thread when the query could not be |
+ // performed because the history system failed to properly init the database. |
+ // If this is set when the main thread is called back, it avoids changing |
+ // |matches_| at all, so it won't delete the default match Start() creates. |
+ bool failed; |
+ |
+ // List of matches written by DoAutocomplete(). Upon its return the provider |
+ // converts this list to ACMatches and places them in |matches_|. |
+ history::HistoryMatches matches; |
+ |
+ // True if the suggestion for exactly what the user typed appears as a known |
+ // URL in the user's history. In this case, this will also be the first match |
+ // in |matches|. |
+ // |
+ // NOTE: There are some complications related to keeping things consistent |
+ // between passes and how we deal with intranet URLs, which are too complex to |
+ // explain here; see the implementations of DoAutocomplete() and |
+ // FixupExactSuggestion() for specific comments. |
+ bool exact_suggestion_is_in_history; |
+ |
+ // Tells the provider whether to promote the what you typed match, the first |
+ // element of |matches|, or neither as the first AutocompleteMatch. If |
+ // |exact_suggestion_is_in_history| is true (and thus "the what you typed |
+ // match" and "the first element of |matches|" represent the same thing), this |
+ // will be set to WHAT_YOU_TYPED_MATCH. |
+ // |
+ // NOTE: The second pass of DoAutocomplete() checks what the first pass set |
+ // this to. See comments in DoAutocomplete(). |
+ PromoteType promote_type; |
+ |
+ // True if |what_you_typed_match| is eligible for display. If this is true, |
+ // PromoteMatchesIfNecessary() may choose to place |what_you_typed_match| on |
+ // |matches_| even when |promote_type| is not WHAT_YOU_TYPED_MATCH. |
+ bool have_what_you_typed_match; |
+ |
+ // Languages we should pass to gfx::GetCleanStringFromUrl. |
+ std::string languages; |
+ |
+ // The default search provider and search terms data necessary to cull results |
+ // that correspond to searches (on the default engine). These can only be |
+ // obtained on the UI thread, so we have to copy them into here to pass them |
+ // to the history thread. We use a scoped_ptr<TemplateURL> for the DSP since |
+ // TemplateURLs can't be copied by value. We use a scoped_ptr<SearchTermsData> |
+ // so that we can store a snapshot of the SearchTermsData accessible from the |
+ // history thread. |
+ scoped_ptr<TemplateURL> default_search_provider; |
+ scoped_ptr<SearchTermsData> search_terms_data; |
+ |
+ private: |
+ DISALLOW_COPY_AND_ASSIGN(HistoryURLProviderParams); |
+}; |
+ |
+// This class is an autocomplete provider and is also a pseudo-internal |
+// component of the history system. See comments above. |
+class HistoryURLProvider : public HistoryProvider { |
+ public: |
+ // Various values used in scoring, made public so other providers |
+ // can insert results in appropriate ranges relative to these. |
+ static const int kScoreForBestInlineableResult; |
+ static const int kScoreForUnvisitedIntranetResult; |
+ static const int kScoreForWhatYouTypedResult; |
+ static const int kBaseScoreForNonInlineableResult; |
+ |
+ HistoryURLProvider(AutocompleteProviderClient* client, |
+ AutocompleteProviderListener* listener); |
+ |
+ // HistoryProvider: |
+ void Start(const AutocompleteInput& input, |
+ bool minimal_changes, |
+ bool called_due_to_focus) override; |
+ void Stop(bool clear_cached_results, bool due_to_user_inactivity) override; |
+ |
+ // Returns a match representing a navigation to |destination_url| given user |
+ // input of |text|. |trim_http| controls whether the match's |fill_into_edit| |
+ // and |contents| should have any HTTP scheme stripped off, and should not be |
+ // set to true if |text| contains an http prefix. |
+ // NOTES: This does not set the relevance of the returned match, as different |
+ // callers want different behavior. Callers must set this manually. |
+ // This function should only be called on the UI thread. |
+ AutocompleteMatch SuggestExactInput(const base::string16& text, |
+ const GURL& destination_url, |
+ bool trim_http); |
+ |
+ // Runs the history query on the history thread, called by the history |
+ // system. The history database MAY BE NULL in which case it is not |
+ // available and we should return no data. Also schedules returning the |
+ // results to the main thread |
+ void ExecuteWithDB(HistoryURLProviderParams* params, |
+ history::HistoryBackend* backend, |
+ history::URLDatabase* db); |
+ |
+ private: |
+ FRIEND_TEST_ALL_PREFIXES(HistoryURLProviderTest, HUPScoringExperiment); |
+ |
+ enum MatchType { |
+ NORMAL, |
+ WHAT_YOU_TYPED, |
+ INLINE_AUTOCOMPLETE, |
+ UNVISITED_INTRANET, // An intranet site that has never been visited. |
+ }; |
+ class VisitClassifier; |
+ |
+ ~HistoryURLProvider() override; |
+ |
+ // Determines the relevance for a match, given its type. If |match_type| is |
+ // NORMAL, |match_number| is a number indicating the relevance of the match |
+ // (higher == more relevant). For other values of |match_type|, |
+ // |match_number| is ignored. Only called some of the time; for some matches, |
+ // relevancy scores are assigned consecutively decreasing (1416, 1415, ...). |
+ static int CalculateRelevance(MatchType match_type, int match_number); |
+ |
+ // Returns a set of classifications that highlight all the occurrences of |
+ // |input_text| at word breaks in |description|. |
+ static ACMatchClassifications ClassifyDescription( |
+ const base::string16& input_text, |
+ const base::string16& description); |
+ |
+ // Actually runs the autocomplete job on the given database, which is |
+ // guaranteed not to be NULL. Used by both autocomplete passes, and therefore |
+ // called on multiple different threads (though not simultaneously). |
+ void DoAutocomplete(history::HistoryBackend* backend, |
+ history::URLDatabase* db, |
+ HistoryURLProviderParams* params); |
+ |
+ // May promote the what you typed match, the first history match in |
+ // params->matches, or both to the front of |matches_|, depending on the |
+ // values of params->promote_type, params->have_what_you_typed_match, and |
+ // params->prevent_inline_autocomplete. |
+ void PromoteMatchesIfNecessary(const HistoryURLProviderParams& params); |
+ |
+ // Dispatches the results to the autocomplete controller. Called on the |
+ // main thread by ExecuteWithDB when the results are available. |
+ // Frees params_gets_deleted on exit. |
+ void QueryComplete(HistoryURLProviderParams* params_gets_deleted); |
+ |
+ // Looks up the info for params->what_you_typed_match in the DB. If found, |
+ // fills in the title, promotes the match's priority to that of an inline |
+ // autocomplete match (maybe it should be slightly better?), and places it on |
+ // the front of params->matches (so we pick the right matches to throw away |
+ // when culling redirects to/from it). Returns whether a match was promoted. |
+ bool FixupExactSuggestion(history::URLDatabase* db, |
+ const VisitClassifier& classifier, |
+ HistoryURLProviderParams* params) const; |
+ |
+ // Helper function for FixupExactSuggestion, this returns true if the input |
+ // corresponds to some intranet URL where the user has previously visited the |
+ // host in question. In this case the input should be treated as a URL. |
+ bool CanFindIntranetURL(history::URLDatabase* db, |
+ const AutocompleteInput& input) const; |
+ |
+ // Sees if a shorter version of the best match should be created, and if so |
+ // places it at the front of params->matches. This can suggest history URLs |
+ // that are prefixes of the best match (if they've been visited enough, |
+ // compared to the best match), or create host-only suggestions even when they |
+ // haven't been visited before: if the user visited http://example.com/asdf |
+ // once, we'll suggest http://example.com/ even if they've never been to it. |
+ // Returns true if a match was successfully created/promoted that we're |
+ // willing to inline autocomplete. |
+ bool PromoteOrCreateShorterSuggestion( |
+ history::URLDatabase* db, |
+ HistoryURLProviderParams* params); |
+ |
+ // Removes results that have been rarely typed or visited, and not any time |
+ // recently. The exact parameters for this heuristic can be found in the |
+ // function body. Also culls results corresponding to queries from the default |
+ // search engine. These are low-quality, difficult-to-understand matches for |
+ // users, and the SearchProvider should surface past queries in a better way |
+ // anyway. |
+ void CullPoorMatches(HistoryURLProviderParams* params) const; |
+ |
+ // Removes results that redirect to each other, leaving at most |max_results| |
+ // results. |
+ void CullRedirects(history::HistoryBackend* backend, |
+ history::HistoryMatches* matches, |
+ size_t max_results) const; |
+ |
+ // Helper function for CullRedirects, this removes all but the first |
+ // occurance of [any of the set of strings in |remove|] from the |matches| |
+ // list. |
+ // |
+ // The return value is the index of the item that is after the item in the |
+ // input identified by |source_index|. If |source_index| or an item before |
+ // is removed, the next item will be shifted, and this allows the caller to |
+ // pick up on the next one when this happens. |
+ size_t RemoveSubsequentMatchesOf(history::HistoryMatches* matches, |
+ size_t source_index, |
+ const std::vector<GURL>& remove) const; |
+ |
+ // Converts a specified |match_number| from params.matches into an |
+ // autocomplete match for display. If experimental scoring is enabled, the |
+ // final relevance score might be different from the given |relevance|. |
+ // NOTE: This function should only be called on the UI thread. |
+ AutocompleteMatch HistoryMatchToACMatch( |
+ const HistoryURLProviderParams& params, |
+ size_t match_number, |
+ MatchType match_type, |
+ int relevance); |
+ |
+ AutocompleteProviderListener* listener_; |
+ |
+ // Params for the current query. The provider should not free this directly; |
+ // instead, it is passed as a parameter through the history backend, and the |
+ // parameter itself is freed once it's no longer needed. The only reason we |
+ // keep this member is so we can set the cancel bit on it. |
+ HistoryURLProviderParams* params_; |
+ |
+ // Params controlling experimental behavior of this provider. |
+ HUPScoringParams scoring_params_; |
+ |
+ base::ThreadChecker thread_checker_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(HistoryURLProvider); |
+}; |
+ |
+#endif // CHROME_BROWSER_AUTOCOMPLETE_HISTORY_URL_PROVIDER_H_ |