OLD | NEW |
(Empty) | |
| 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 COMPONENTS_OMNIBOX_HISTORY_URL_PROVIDER_H_ |
| 6 #define COMPONENTS_OMNIBOX_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 "base/threading/thread_checker.h" |
| 14 #include "components/history/core/browser/history_match.h" |
| 15 #include "components/omnibox/autocomplete_input.h" |
| 16 #include "components/omnibox/history_provider.h" |
| 17 #include "components/omnibox/omnibox_field_trial.h" |
| 18 #include "components/search_engines/template_url.h" |
| 19 |
| 20 class AutocompleteProviderListener; |
| 21 class SearchTermsData; |
| 22 |
| 23 namespace base { |
| 24 class MessageLoop; |
| 25 } |
| 26 |
| 27 namespace history { |
| 28 class HistoryBackend; |
| 29 class URLDatabase; |
| 30 } |
| 31 |
| 32 // How history autocomplete works |
| 33 // ============================== |
| 34 // |
| 35 // Read down this diagram for temporal ordering. |
| 36 // |
| 37 // Main thread History thread |
| 38 // ----------- -------------- |
| 39 // AutocompleteController::Start |
| 40 // -> HistoryURLProvider::Start |
| 41 // -> SuggestExactInput |
| 42 // [params_ allocated] |
| 43 // -> DoAutocomplete (for inline autocomplete) |
| 44 // -> URLDatabase::AutocompleteForPrefix (on in-memory DB) |
| 45 // -> HistoryService::ScheduleAutocomplete |
| 46 // (return to controller) ---- |
| 47 // / |
| 48 // HistoryBackend::ScheduleAutocomplete |
| 49 // -> HistoryURLProvider::ExecuteWithDB |
| 50 // -> DoAutocomplete |
| 51 // -> URLDatabase::AutocompleteForPrefix |
| 52 // / |
| 53 // HistoryService::QueryComplete |
| 54 // [params_ destroyed] |
| 55 // -> AutocompleteProviderListener::OnProviderUpdate |
| 56 // |
| 57 // The autocomplete controller calls us, and must be called back, on the main |
| 58 // thread. When called, we run two autocomplete passes. The first pass runs |
| 59 // synchronously on the main thread and queries the in-memory URL database. |
| 60 // This pass promotes matches for inline autocomplete if applicable. We do |
| 61 // this synchronously so that users get consistent behavior when they type |
| 62 // quickly and hit enter, no matter how loaded the main history database is. |
| 63 // Doing this synchronously also prevents inline autocomplete from being |
| 64 // "flickery" in the AutocompleteEdit. Because the in-memory DB does not have |
| 65 // redirect data, results other than the top match might change between the |
| 66 // two passes, so we can't just decide to use this pass' matches as the final |
| 67 // results. |
| 68 // |
| 69 // The second autocomplete pass uses the full history database, which must be |
| 70 // queried on the history thread. Start() asks the history service schedule to |
| 71 // callback on the history thread with a pointer to the main database. When we |
| 72 // are done doing queries, we schedule a task on the main thread that notifies |
| 73 // the AutocompleteController that we're done. |
| 74 // |
| 75 // The communication between these threads is done using a |
| 76 // HistoryURLProviderParams object. This is allocated in the main thread, and |
| 77 // normally deleted in QueryComplete(). So that both autocomplete passes can |
| 78 // use the same code, we also use this to hold results during the first |
| 79 // autocomplete pass. |
| 80 // |
| 81 // While the second pass is running, the AutocompleteController may cancel the |
| 82 // request. This can happen frequently when the user is typing quickly. In |
| 83 // this case, the main thread sets params_->cancel, which the background thread |
| 84 // checks periodically. If it finds the flag set, it stops what it's doing |
| 85 // immediately and calls back to the main thread. (We don't delete the params |
| 86 // on the history thread, because we should only do that when we can safely |
| 87 // NULL out params_, and that must be done on the main thread.) |
| 88 |
| 89 // Used to communicate autocomplete parameters between threads via the history |
| 90 // service. |
| 91 struct HistoryURLProviderParams { |
| 92 // See comments on |promote_type| below. |
| 93 enum PromoteType { |
| 94 WHAT_YOU_TYPED_MATCH, |
| 95 FRONT_HISTORY_MATCH, |
| 96 NEITHER, |
| 97 }; |
| 98 |
| 99 HistoryURLProviderParams(const AutocompleteInput& input, |
| 100 bool trim_http, |
| 101 const AutocompleteMatch& what_you_typed_match, |
| 102 const std::string& languages, |
| 103 TemplateURL* default_search_provider, |
| 104 const SearchTermsData& search_terms_data); |
| 105 ~HistoryURLProviderParams(); |
| 106 |
| 107 base::MessageLoop* message_loop; |
| 108 |
| 109 // A copy of the autocomplete input. We need the copy since this object will |
| 110 // live beyond the original query while it runs on the history thread. |
| 111 AutocompleteInput input; |
| 112 |
| 113 // Should inline autocompletion be disabled? This is initalized from |
| 114 // |input.prevent_inline_autocomplete()|, but set to false is the input |
| 115 // contains trailing white space. |
| 116 bool prevent_inline_autocomplete; |
| 117 |
| 118 // Set when "http://" should be trimmed from the beginning of the URLs. |
| 119 bool trim_http; |
| 120 |
| 121 // A match corresponding to what the user typed. |
| 122 AutocompleteMatch what_you_typed_match; |
| 123 |
| 124 // Set by the main thread to cancel this request. If this flag is set when |
| 125 // the query runs, the query will be abandoned. This allows us to avoid |
| 126 // running queries that are no longer needed. Since we don't care if we run |
| 127 // the extra queries, the lack of signaling is not a problem. |
| 128 base::CancellationFlag cancel_flag; |
| 129 |
| 130 // Set by ExecuteWithDB() on the history thread when the query could not be |
| 131 // performed because the history system failed to properly init the database. |
| 132 // If this is set when the main thread is called back, it avoids changing |
| 133 // |matches_| at all, so it won't delete the default match Start() creates. |
| 134 bool failed; |
| 135 |
| 136 // List of matches written by DoAutocomplete(). Upon its return the provider |
| 137 // converts this list to ACMatches and places them in |matches_|. |
| 138 history::HistoryMatches matches; |
| 139 |
| 140 // True if the suggestion for exactly what the user typed appears as a known |
| 141 // URL in the user's history. In this case, this will also be the first match |
| 142 // in |matches|. |
| 143 // |
| 144 // NOTE: There are some complications related to keeping things consistent |
| 145 // between passes and how we deal with intranet URLs, which are too complex to |
| 146 // explain here; see the implementations of DoAutocomplete() and |
| 147 // FixupExactSuggestion() for specific comments. |
| 148 bool exact_suggestion_is_in_history; |
| 149 |
| 150 // Tells the provider whether to promote the what you typed match, the first |
| 151 // element of |matches|, or neither as the first AutocompleteMatch. If |
| 152 // |exact_suggestion_is_in_history| is true (and thus "the what you typed |
| 153 // match" and "the first element of |matches|" represent the same thing), this |
| 154 // will be set to WHAT_YOU_TYPED_MATCH. |
| 155 // |
| 156 // NOTE: The second pass of DoAutocomplete() checks what the first pass set |
| 157 // this to. See comments in DoAutocomplete(). |
| 158 PromoteType promote_type; |
| 159 |
| 160 // True if |what_you_typed_match| is eligible for display. If this is true, |
| 161 // PromoteMatchesIfNecessary() may choose to place |what_you_typed_match| on |
| 162 // |matches_| even when |promote_type| is not WHAT_YOU_TYPED_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(AutocompleteProviderClient* client, |
| 194 AutocompleteProviderListener* listener); |
| 195 |
| 196 // HistoryProvider: |
| 197 void Start(const AutocompleteInput& input, |
| 198 bool minimal_changes, |
| 199 bool called_due_to_focus) override; |
| 200 void Stop(bool clear_cached_results, bool due_to_user_inactivity) override; |
| 201 |
| 202 // Returns a match representing a navigation to |destination_url| given user |
| 203 // input of |text|. |trim_http| controls whether the match's |fill_into_edit| |
| 204 // and |contents| should have any HTTP scheme stripped off, and should not be |
| 205 // set to true if |text| contains an http prefix. |
| 206 // NOTES: This does not set the relevance of the returned match, as different |
| 207 // callers want different behavior. Callers must set this manually. |
| 208 // This function should only be called on the UI thread. |
| 209 AutocompleteMatch SuggestExactInput(const base::string16& text, |
| 210 const GURL& destination_url, |
| 211 bool trim_http); |
| 212 |
| 213 // Runs the history query on the history thread, called by the history |
| 214 // system. The history database MAY BE NULL in which case it is not |
| 215 // available and we should return no data. Also schedules returning the |
| 216 // results to the main thread |
| 217 void ExecuteWithDB(HistoryURLProviderParams* params, |
| 218 history::HistoryBackend* backend, |
| 219 history::URLDatabase* db); |
| 220 |
| 221 private: |
| 222 FRIEND_TEST_ALL_PREFIXES(HistoryURLProviderTest, HUPScoringExperiment); |
| 223 |
| 224 enum MatchType { |
| 225 NORMAL, |
| 226 WHAT_YOU_TYPED, |
| 227 INLINE_AUTOCOMPLETE, |
| 228 UNVISITED_INTRANET, // An intranet site that has never been visited. |
| 229 }; |
| 230 class VisitClassifier; |
| 231 |
| 232 ~HistoryURLProvider() override; |
| 233 |
| 234 // Determines the relevance for a match, given its type. If |match_type| is |
| 235 // NORMAL, |match_number| is a number indicating the relevance of the match |
| 236 // (higher == more relevant). For other values of |match_type|, |
| 237 // |match_number| is ignored. Only called some of the time; for some matches, |
| 238 // relevancy scores are assigned consecutively decreasing (1416, 1415, ...). |
| 239 static int CalculateRelevance(MatchType match_type, int match_number); |
| 240 |
| 241 // Returns a set of classifications that highlight all the occurrences of |
| 242 // |input_text| at word breaks in |description|. |
| 243 static ACMatchClassifications ClassifyDescription( |
| 244 const base::string16& input_text, |
| 245 const base::string16& description); |
| 246 |
| 247 // Actually runs the autocomplete job on the given database, which is |
| 248 // guaranteed not to be NULL. Used by both autocomplete passes, and therefore |
| 249 // called on multiple different threads (though not simultaneously). |
| 250 void DoAutocomplete(history::HistoryBackend* backend, |
| 251 history::URLDatabase* db, |
| 252 HistoryURLProviderParams* params); |
| 253 |
| 254 // May promote the what you typed match, the first history match in |
| 255 // params->matches, or both to the front of |matches_|, depending on the |
| 256 // values of params->promote_type, params->have_what_you_typed_match, and |
| 257 // params->prevent_inline_autocomplete. |
| 258 void PromoteMatchesIfNecessary(const HistoryURLProviderParams& params); |
| 259 |
| 260 // Dispatches the results to the autocomplete controller. Called on the |
| 261 // main thread by ExecuteWithDB when the results are available. |
| 262 // Frees params_gets_deleted on exit. |
| 263 void QueryComplete(HistoryURLProviderParams* params_gets_deleted); |
| 264 |
| 265 // Looks up the info for params->what_you_typed_match in the DB. If found, |
| 266 // fills in the title, promotes the match's priority to that of an inline |
| 267 // autocomplete match (maybe it should be slightly better?), and places it on |
| 268 // the front of params->matches (so we pick the right matches to throw away |
| 269 // when culling redirects to/from it). Returns whether a match was promoted. |
| 270 bool FixupExactSuggestion(history::URLDatabase* db, |
| 271 const VisitClassifier& classifier, |
| 272 HistoryURLProviderParams* params) const; |
| 273 |
| 274 // Helper function for FixupExactSuggestion, this returns true if the input |
| 275 // corresponds to some intranet URL where the user has previously visited the |
| 276 // host in question. In this case the input should be treated as a URL. |
| 277 bool CanFindIntranetURL(history::URLDatabase* db, |
| 278 const AutocompleteInput& input) const; |
| 279 |
| 280 // Sees if a shorter version of the best match should be created, and if so |
| 281 // places it at the front of params->matches. This can suggest history URLs |
| 282 // that are prefixes of the best match (if they've been visited enough, |
| 283 // compared to the best match), or create host-only suggestions even when they |
| 284 // haven't been visited before: if the user visited http://example.com/asdf |
| 285 // once, we'll suggest http://example.com/ even if they've never been to it. |
| 286 // Returns true if a match was successfully created/promoted that we're |
| 287 // willing to inline autocomplete. |
| 288 bool PromoteOrCreateShorterSuggestion( |
| 289 history::URLDatabase* db, |
| 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 AutocompleteProviderListener* listener_; |
| 329 |
| 330 // Params for the current query. The provider should not free this directly; |
| 331 // instead, it is passed as a parameter through the history backend, and the |
| 332 // parameter itself is freed once it's no longer needed. The only reason we |
| 333 // keep this member is so we can set the cancel bit on it. |
| 334 HistoryURLProviderParams* params_; |
| 335 |
| 336 // Params controlling experimental behavior of this provider. |
| 337 HUPScoringParams scoring_params_; |
| 338 |
| 339 base::ThreadChecker thread_checker_; |
| 340 |
| 341 DISALLOW_COPY_AND_ASSIGN(HistoryURLProvider); |
| 342 }; |
| 343 |
| 344 #endif // COMPONENTS_OMNIBOX_HISTORY_URL_PROVIDER_H_ |
OLD | NEW |