diff options
author | pkasting@chromium.org <pkasting@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-10-09 18:21:27 +0000 |
---|---|---|
committer | pkasting@chromium.org <pkasting@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-10-09 18:21:27 +0000 |
commit | 8deeb95696562494db58140a46fbe06432f39d57 (patch) | |
tree | e74fed0de316dd2bc97805b0ba2a942fb8d53aff /chrome/browser/autocomplete | |
parent | 3b2a95c36e98d35b417466054349d2d5308c2af3 (diff) | |
download | chromium_src-8deeb95696562494db58140a46fbe06432f39d57.zip chromium_src-8deeb95696562494db58140a46fbe06432f39d57.tar.gz chromium_src-8deeb95696562494db58140a46fbe06432f39d57.tar.bz2 |
Move |result_| and |latest_result_| to the autocomplete controller.
This purposefully does not change the communication interface between the edit and the popup; that's coming in a subsequent pass. As a result, right now the popup isn't really much simpler. That should eventually change.
Review URL: http://codereview.chromium.org/6596
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@3113 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/autocomplete')
18 files changed, 517 insertions, 529 deletions
diff --git a/chrome/browser/autocomplete/autocomplete.cc b/chrome/browser/autocomplete/autocomplete.cc index e6ab849..9001b11 100644 --- a/chrome/browser/autocomplete/autocomplete.cc +++ b/chrome/browser/autocomplete/autocomplete.cc @@ -32,10 +32,12 @@ AutocompleteInput::AutocompleteInput(const std::wstring& text, const std::wstring& desired_tld, bool prevent_inline_autocomplete, - bool prefer_keyword) + bool prefer_keyword, + bool synchronous_only) : desired_tld_(desired_tld), prevent_inline_autocomplete_(prevent_inline_autocomplete), - prefer_keyword_(prefer_keyword) { + prefer_keyword_(prefer_keyword), + synchronous_only_(synchronous_only) { // Trim whitespace from edges of input; don't inline autocomplete if there // was trailing whitespace. if (TrimWhitespace(text, TRIM_ALL, &text_) & TRIM_TRAILING) @@ -216,7 +218,8 @@ bool AutocompleteInput::Equals(const AutocompleteInput& other) const { (desired_tld_ == other.desired_tld_) && (scheme_ == other.scheme_) && (prevent_inline_autocomplete_ == other.prevent_inline_autocomplete_) && - (prefer_keyword_ == other.prefer_keyword_); + (prefer_keyword_ == other.prefer_keyword_) && + (synchronous_only_ == other.synchronous_only_); } void AutocompleteInput::Clear() { @@ -513,20 +516,24 @@ void AutocompleteResult::Validate() const { const int AutocompleteController::kNoItemSelected = -1; -AutocompleteController::AutocompleteController(ACControllerListener* listener, - Profile* profile) - : listener_(listener) { +namespace { +// The amount of time we'll wait after a provider returns before updating, +// in order to coalesce results. +const int kResultCoalesceMs = 100; + +// The maximum time we'll allow the results to go without updating to the +// latest set. +const int kResultUpdateMaxDelayMs = 300; +}; + +AutocompleteController::AutocompleteController(Profile* profile) + : update_pending_(false), + done_(true) { providers_.push_back(new SearchProvider(this, profile)); providers_.push_back(new HistoryURLProvider(this, profile)); providers_.push_back(new KeywordProvider(this, profile)); - if (listener) { - // These providers are async-only, so there's no need to create them when - // we'll only be doing synchronous queries. - history_contents_provider_ = new HistoryContentsProvider(this, profile); - providers_.push_back(history_contents_provider_); - } else { - history_contents_provider_ = NULL; - } + history_contents_provider_ = new HistoryContentsProvider(this, profile); + providers_.push_back(history_contents_provider_); for (ACProviders::iterator i(providers_.begin()); i != providers_.end(); ++i) (*i)->AddRef(); } @@ -543,79 +550,161 @@ void AutocompleteController::SetProfile(Profile* profile) { (*i)->SetProfile(profile); } -bool AutocompleteController::Start(const AutocompleteInput& input, - bool minimal_changes, +void AutocompleteController::Start(const std::wstring& text, + const std::wstring& desired_tld, + bool prevent_inline_autocomplete, + bool prefer_keyword, bool synchronous_only) { - input_ = input; + // See if we can avoid rerunning autocomplete when the query hasn't changed + // much. When the user presses or releases the ctrl key, the desired_tld + // changes, and when the user finishes an IME composition, inline autocomplete + // may no longer be prevented. In both these cases the text itself hasn't + // changed since the last query, and some providers can do much less work (and + // get results back more quickly). Taking advantage of this reduces flicker. + const bool minimal_changes = (input_.text() == text) && + (input_.synchronous_only() == synchronous_only); + input_ = AutocompleteInput(text, desired_tld, prevent_inline_autocomplete, + prefer_keyword, synchronous_only); + + // If we're starting a brand new query, stop caring about any old query. + if (!minimal_changes && !done_) { + update_pending_ = false; + coalesce_timer_.Stop(); + } + + // Start the new query. for (ACProviders::iterator i(providers_.begin()); i != providers_.end(); ++i) { - (*i)->Start(input, minimal_changes, synchronous_only); + (*i)->Start(input_, minimal_changes); if (synchronous_only) DCHECK((*i)->done()); } - - return QueryComplete(); + UpdateLatestResult(true); } -void AutocompleteController::Stop() const { +void AutocompleteController::Stop(bool clear_result) { for (ACProviders::const_iterator i(providers_.begin()); i != providers_.end(); ++i) { if (!(*i)->done()) (*i)->Stop(); } + + done_ = true; + update_pending_ = false; + if (clear_result) + result_.Reset(); + latest_result_.CopyFrom(result_); // Not strictly necessary, but keeps + // internal state consistent. + coalesce_timer_.Stop(); + max_delay_timer_.Stop(); +} + +void AutocompleteController::DeleteMatch(const AutocompleteMatch& match) { + DCHECK(match.deletable); + match.provider->DeleteMatch(match); // This will synchronously call back to + // OnProviderUpdate(). + + // Notify observers of this change immediately, so the UI feels responsive to + // the user's action. + if (update_pending_) + CommitResult(); } void AutocompleteController::OnProviderUpdate(bool updated_matches) { - // Notify listener when something has changed. - if (!listener_) { - NOTREACHED(); // This should never be called for synchronous queries, and - // since |listener_| is NULL, the owner of the controller - // should only be running synchronous queries. - return; // But, this isn't fatal, so don't crash. + DCHECK(!input_.synchronous_only()); + + if (updated_matches) { + UpdateLatestResult(false); + return; + } + + done_ = true; + for (ACProviders::const_iterator i(providers_.begin()); + i != providers_.end(); ++i) { + if (!(*i)->done()) { + done_ = false; + return; + } } - const bool query_complete = QueryComplete(); - if (updated_matches || query_complete) - listener_->OnAutocompleteUpdate(updated_matches, query_complete); + // In theory we could call Stop() instead of CommitLatestResults() here if we + // knew we'd already called CommitLatestResults() at least once for this + // query. In practice, our observers don't do enough work responding to the + // updates here for the potentially-extra notification to matter. + CommitResult(); } -void AutocompleteController::GetResult(AutocompleteResult* result) { +void AutocompleteController::UpdateLatestResult(bool is_synchronous_pass) { // Add all providers' results. - result->Reset(); + latest_result_.Reset(); + done_ = true; for (ACProviders::const_iterator i(providers_.begin()); - i != providers_.end(); ++i) - result->AppendMatches((*i)->matches()); + i != providers_.end(); ++i) { + latest_result_.AppendMatches((*i)->matches()); + if (!(*i)->done()) + done_ = false; + } // Sort the matches and trim to a small number of "best" matches. - result->SortAndCull(); + latest_result_.SortAndCull(); if (history_contents_provider_) - AddHistoryContentsShortcut(result); + AddHistoryContentsShortcut(); #ifndef NDEBUG - result->Validate(); + latest_result_.Validate(); #endif -} -bool AutocompleteController::QueryComplete() const { - for (ACProviders::const_iterator i(providers_.begin()); - i != providers_.end(); ++i) { - if (!(*i)->done()) - return false; + if (is_synchronous_pass) { + if (!max_delay_timer_.IsRunning()) { + max_delay_timer_.Start( + TimeDelta::FromMilliseconds(kResultUpdateMaxDelayMs), + this, &AutocompleteController::CommitResult); + } + + result_.CopyFrom(latest_result_); + NotificationService::current()->Notify( + NOTIFY_AUTOCOMPLETE_CONTROLLER_SYNCHRONOUS_MATCHES_AVAILABLE, + Source<AutocompleteController>(this), NotificationService::NoDetails()); } - return true; + if (done_) { + CommitResult(); + } else if (!update_pending_) { + // Coalesce the results for the next kPopupCoalesceMs milliseconds. + update_pending_ = true; + coalesce_timer_.Stop(); + coalesce_timer_.Start(TimeDelta::FromMilliseconds(kResultCoalesceMs), this, + &AutocompleteController::CommitResult); + } +} + +void AutocompleteController::CommitResult() { + // The max update interval timer either needs to be reset (if more updates + // are to come) or stopped (when we're done with the query). The coalesce + // timer should always just be stopped. + update_pending_ = false; + coalesce_timer_.Stop(); + if (done_) + max_delay_timer_.Stop(); + else + max_delay_timer_.Reset(); + + result_.CopyFrom(latest_result_); + NotificationService::current()->Notify( + NOTIFY_AUTOCOMPLETE_CONTROLLER_RESULT_UPDATED, + Source<AutocompleteController>(this), NotificationService::NoDetails()); } -size_t AutocompleteController::CountMatchesNotInResult( +size_t AutocompleteController::CountMatchesNotInLatestResult( const AutocompleteProvider* provider, - const AutocompleteResult* result, - AutocompleteMatch* first_match) { - DCHECK(provider && result && first_match); + AutocompleteMatch* first_match) const { + DCHECK(provider); + DCHECK(first_match); // Determine the set of destination URLs. std::set<std::wstring> destination_urls; - for (AutocompleteResult::const_iterator i(result->begin()); - i != result->end(); ++i) + for (AutocompleteResult::const_iterator i(latest_result_.begin()); + i != latest_result_.end(); ++i) destination_urls.insert(i->destination_url); const ACMatches& provider_matches = provider->matches(); @@ -633,9 +722,8 @@ size_t AutocompleteController::CountMatchesNotInResult( return provider_matches.size() - showing_count; } -void AutocompleteController::AddHistoryContentsShortcut( - AutocompleteResult* result) { - DCHECK(result && history_contents_provider_); +void AutocompleteController::AddHistoryContentsShortcut() { + DCHECK(history_contents_provider_); // Only check the history contents provider if the history contents provider // is done and has matches. if (!history_contents_provider_->done() || @@ -643,12 +731,13 @@ void AutocompleteController::AddHistoryContentsShortcut( return; } - if ((history_contents_provider_->db_match_count() <= result->size() + 1) || - history_contents_provider_->db_match_count() == 1) { + if ((history_contents_provider_->db_match_count() <= + (latest_result_.size() + 1)) || + (history_contents_provider_->db_match_count() == 1)) { // We only want to add a shortcut if we're not already showing the matches. AutocompleteMatch first_unique_match; - size_t matches_not_shown = CountMatchesNotInResult( - history_contents_provider_, result, &first_unique_match); + size_t matches_not_shown = CountMatchesNotInLatestResult( + history_contents_provider_, &first_unique_match); if (matches_not_shown == 0) return; if (matches_not_shown == 1) { @@ -656,7 +745,7 @@ void AutocompleteController::AddHistoryContentsShortcut( // which means we need to negate it to get the true relevance. if (first_unique_match.relevance < 0) first_unique_match.relevance = -first_unique_match.relevance; - result->AddMatch(first_unique_match); + latest_result_.AddMatch(first_unique_match); return; } // else, fall through and add item. } @@ -710,5 +799,5 @@ void AutocompleteController::AddHistoryContentsShortcut( input_.text()).spec()); match.transition = PageTransition::AUTO_BOOKMARK; match.provider = history_contents_provider_; - result->AddMatch(match); + latest_result_.AddMatch(match); } diff --git a/chrome/browser/autocomplete/autocomplete.h b/chrome/browser/autocomplete/autocomplete.h index cbf4faf..78b03a2 100644 --- a/chrome/browser/autocomplete/autocomplete.h +++ b/chrome/browser/autocomplete/autocomplete.h @@ -10,20 +10,20 @@ #include <vector> #include "base/logging.h" #include "base/ref_counted.h" +#include "base/timer.h" #include "chrome/common/page_transition_types.h" #include "googleurl/src/url_parse.h" // The AutocompleteController is the center of the autocomplete system. A -// class implementing AutocompleteController::Listener creates an instance of -// the controller, which in turn creates a set of AutocompleteProviders to -// serve it. The listener can ask the controller to Start() a query; the -// controller in turn passes this call down to the providers, each of which -// keeps track of its own results and whether it has finished processing the -// query. When a provider gets more results or finishes processing, it -// notifies the controller, which merges the combined results together and -// returns them to the listener. +// class creates an instance of the controller, which in turn creates a set of +// AutocompleteProviders to serve it. The owning class can ask the controller +// to Start() a query; the controller in turn passes this call down to the +// providers, each of which keeps track of its own results and whether it has +// finished processing the query. When a provider gets more results or finishes +// processing, it notifies the controller, which merges the combined results +// together and makes them available to interested observers. // -// The listener may also cancel the current query by calling Stop(), which the +// The owner may also cancel the current query by calling Stop(), which the // controller will in turn communicate to all the providers. No callbacks will // happen after a request has been stopped. // @@ -152,13 +152,15 @@ class AutocompleteInput { AutocompleteInput() : type_(INVALID), prevent_inline_autocomplete_(false), - prefer_keyword_(false) { + prefer_keyword_(false), + synchronous_only_(false) { } AutocompleteInput(const std::wstring& text, const std::wstring& desired_tld, bool prevent_inline_autocomplete, - bool prefer_keyword); + bool prefer_keyword, + bool synchronous_only); // Parses |text| and returns the type of input this will be interpreted as. // The components of the input are stored in the output parameter |parts|. @@ -197,6 +199,12 @@ class AutocompleteInput { // keyword, we should score it like a non-substituting keyword. const bool prefer_keyword() const { return prefer_keyword_; } + // Returns whether providers should avoid scheduling asynchronous work. If + // this is true, providers should stop after returning all the + // synchronously-available results. This also means any in-progress + // asynchronous work should be canceled, so no later callbacks are fired. + const bool synchronous_only() const { return synchronous_only_; } + // operator==() by another name. bool Equals(const AutocompleteInput& other) const; @@ -214,6 +222,7 @@ class AutocompleteInput { std::wstring desired_tld_; bool prevent_inline_autocomplete_; bool prefer_keyword_; + bool synchronous_only_; }; // AutocompleteMatch ---------------------------------------------------------- @@ -459,15 +468,8 @@ class AutocompleteProvider // |minimal_changes| is an optimization that lets the provider do less work // when the |input|'s text hasn't changed. See the body of // AutocompletePopupModel::StartAutocomplete(). - // - // If |synchronous_only| is true, no asynchronous work should be scheduled; - // the provider should stop after it has returned all the - // synchronously-available results. This also means any in-progress - // asynchronous work should be canceled, so the provider does not call back at - // a later time. virtual void Start(const AutocompleteInput& input, - bool minimal_changes, - bool synchronous_only) = 0; + bool minimal_changes) = 0; // Called when a provider must not make any more callbacks for the current // query. @@ -648,23 +650,9 @@ class AutocompleteResult { // AutocompleteController ----------------------------------------------------- // The coordinator for autocomplete queries, responsible for combining the -// results from a series of providers into one AutocompleteResult and -// interacting with the Listener that owns it. +// results from a series of providers into one AutocompleteResult. class AutocompleteController : public ACProviderListener { public: - class ACControllerListener { - public: - // Called by the controller when new results are available and/or the query - // is complete. The listener can then call GetResult() and provide an - // AutocompleteResult* to be filled in. - // - // Note that this function is never called for synchronous_only queries - // (see Start()). If you're only using those, you can create the controller - // with a NULL listener. - virtual void OnAutocompleteUpdate(bool updated_result, - bool query_complete) = 0; - }; - // Used to indicate an index that is not selected in a call to Update() // and for merging results. static const int kNoItemSelected; @@ -673,16 +661,13 @@ class AutocompleteController : public ACProviderListener { // second to set the providers to some known testing providers. The default // providers will be overridden and the controller will take ownership of the // providers, Release()ing them on destruction. - // - // It is safe to pass NULL for |listener| iff you only ever use synchronous - // queries. - AutocompleteController(ACControllerListener* listener, Profile* profile); + explicit AutocompleteController(Profile* profile); #ifdef UNIT_TEST - AutocompleteController(ACControllerListener* listener, - const ACProviders& providers) - : listener_(listener), - providers_(providers), - history_contents_provider_(NULL) { + explicit AutocompleteController(const ACProviders& providers) + : providers_(providers), + history_contents_provider_(NULL), + update_pending_(false), + done_(true) { } #endif ~AutocompleteController(); @@ -695,51 +680,71 @@ class AutocompleteController : public ACProviderListener { // done or the query is Stop()ed. It is safe to Start() a new query without // Stop()ing the previous one. // - // If |minimal_changes| is true, |input| is the same as in the previous - // query, except for a different desired_tld_ and possibly type_. Most - // providers should just be able to recalculate priorities in this case and - // return synchronously, or at least faster than otherwise. + // |prevent_inline_autocomplete| is true if the generated result set should + // not require inline autocomplete for the default match. This is difficult + // to explain in the abstract; the practical use case is that after the user + // deletes text in the edit, the HistoryURLProvider should make sure not to + // promote a match requiring inline autocomplete too highly. + // + // |prefer_keyword| should be true when the keyword UI is onscreen; this will + // bias the autocomplete results toward the keyword provider when the input + // string is a bare keyword. // // If |synchronous_only| is true, the controller asks the providers to only // return results which are synchronously available, which should mean that // all providers will be done immediately. // - // The controller does not notify the listener about any results available - // immediately; the caller should call GetResult() manually if it wants - // these. The return value is whether the query is complete; if it is - // false, then the controller will call OnAutocompleteUpdate() with future - // result updates (unless the query is Stop()ed). - bool Start(const AutocompleteInput& input, - bool minimal_changes, + // The controller will fire + // NOTIFY_AUTOCOMPLETE_CONTROLLER_SYNCHRONOUS_RESULTS_AVAILABLE from inside + // this call, and unless the query is stopped, will fire at least one (and + // prehaps more) NOTIFY_AUTOCOMPLETE_CONTROLLER_RESULTS_UPDATED later as more + // results come in (even if the query completes synchronously). + void Start(const std::wstring& text, + const std::wstring& desired_tld, + bool prevent_inline_autocomplete, + bool prefer_keyword, bool synchronous_only); - // Cancels the current query, ensuring there will be no future callbacks to - // OnAutocompleteUpdate() (until Start() is called again). - void Stop() const; + // Cancels the current query, ensuring there will be no future notifications + // fired. If new matches have come in since the most recent notification was + // fired, they will be discarded. + // + // If |clear_result| is true, the controller will also erase the result set. + // TODO(pkasting): This is temporary. Instead, we should keep a separate + // result set that tracks the displayed matches. + void Stop(bool clear_result); - // Called by the listener to get the current results of the query. - void GetResult(AutocompleteResult* result); + // Asks the relevant provider to delete |match|, and ensures observers are + // notified of resulting changes immediately. + void DeleteMatch(const AutocompleteMatch& match); + + // Getters + const AutocompleteInput& input() const { return input_; } + const AutocompleteResult& result() const { return result_; } + const bool done() const { return done_; } // From AutocompleteProvider::Listener virtual void OnProviderUpdate(bool updated_matches); private: - // Returns true if all providers have finished processing the query. - bool QueryComplete() const; + // Updates |latest_result_| and |done_| to reflect the current provider state. + // Resets timers and fires notifications as necessary. |is_synchronous_pass| + // is true only when Start() is calling this to get the synchronous results. + void UpdateLatestResult(bool is_synchronous_pass); + + // Copies |latest_result_| to |result_| and notifies observers of updates. + void CommitResult(); // Returns the number of matches from provider whose destination urls are - // not in result. first_match is set to the first match whose destination url - // is NOT in result. - size_t CountMatchesNotInResult(const AutocompleteProvider* provider, - const AutocompleteResult* result, - AutocompleteMatch* first_match); + // not in |latest_result_|. first_match is set to the first match whose + // destination url is NOT in the results. + size_t CountMatchesNotInLatestResult(const AutocompleteProvider* provider, + AutocompleteMatch* first_match) const; // If the HistoryContentsAutocomplete provider is done and there are more // matches in the database than currently shown, an entry is added to - // result to show all history matches. - void AddHistoryContentsShortcut(AutocompleteResult* result); - - ACControllerListener* listener_; // May be NULL. + // |latest_result_| to show all history matches. + void AddHistoryContentsShortcut(); // A list of all providers. ACProviders providers_; @@ -749,11 +754,36 @@ class AutocompleteController : public ACProviderListener { // Input passed to Start. AutocompleteInput input_; + // Data from the autocomplete query. + AutocompleteResult result_; + + // The latest result available from the autocomplete providers. This may be + // different than result_ if we've gotten results from our providers that we + // haven't yet shown the user. If more matches may be coming, we'll wait to + // display these in hopes of minimizing flicker in GUI observers; see + // |coalesce_timer_|. + AutocompleteResult latest_result_; + + // True when there are newer results in |latest_result_| than in |result_| and + // observers have not been notified about them. + bool update_pending_; + + // True if a query is not currently running. + bool done_; + + // Timer that tracks how long it's been since the last provider update we + // received. Instead of notifying about each update immediately, we batch + // updates into groups. + base::OneShotTimer<AutocompleteController> coalesce_timer_; + + // Timer that tracks how long it's been since the last time we updated the + // onscreen results. This is used to ensure that observers update somewhat + // responsively even when the user types continuously. + base::RepeatingTimer<AutocompleteController> max_delay_timer_; + DISALLOW_EVIL_CONSTRUCTORS(AutocompleteController); }; -typedef AutocompleteController::ACControllerListener ACControllerListener; - // AutocompleteLog ------------------------------------------------------------ // The data to log (via the metrics service) when the user selects an item diff --git a/chrome/browser/autocomplete/autocomplete_edit.cc b/chrome/browser/autocomplete/autocomplete_edit.cc index 5a36169..e262e1a 100644 --- a/chrome/browser/autocomplete/autocomplete_edit.cc +++ b/chrome/browser/autocomplete/autocomplete_edit.cc @@ -69,10 +69,9 @@ AutocompleteEditModel::AutocompleteEditModel( show_search_hint_(true), profile_(profile) { if (++paste_and_go_controller_refcount == 1) { - // We don't have a controller yet, so create one. No listener is needed - // since we'll only be doing synchronous calls, and no profile is set since + // We don't have a controller yet, so create one. No profile is set since // we'll set this before each call to the controller. - paste_and_go_controller = new AutocompleteController(NULL, NULL); + paste_and_go_controller = new AutocompleteController(NULL); } } @@ -209,21 +208,15 @@ bool AutocompleteEditModel::CanPasteAndGo(const std::wstring& text) const { paste_and_go_transition_ = PageTransition::TYPED; paste_and_go_alternate_nav_url_.clear(); - // See if the clipboard text can be parsed. - const AutocompleteInput input(text, std::wstring(), true, false); - if (input.type() == AutocompleteInput::INVALID) - return false; - // Ask the controller what do do with this input. paste_and_go_controller->SetProfile(profile_); // This is cheap, and since there's one // paste_and_go_controller for many tabs which // may all have different profiles, it ensures // we're always using the right one. - const bool done = paste_and_go_controller->Start(input, false, true); - DCHECK(done); - AutocompleteResult result; - paste_and_go_controller->GetResult(&result); + paste_and_go_controller->Start(text, std::wstring(), true, false, true); + DCHECK(paste_and_go_controller->done()); + const AutocompleteResult& result = paste_and_go_controller->result(); if (result.empty()) return false; @@ -232,7 +225,8 @@ bool AutocompleteEditModel::CanPasteAndGo(const std::wstring& text) const { DCHECK(match != result.end()); paste_and_go_url_ = match->destination_url; paste_and_go_transition_ = match->transition; - paste_and_go_alternate_nav_url_ = result.GetAlternateNavURL(input, match); + paste_and_go_alternate_nav_url_ = + result.GetAlternateNavURL(paste_and_go_controller->input(), match); return !paste_and_go_url_.empty(); } @@ -335,11 +329,11 @@ void AutocompleteEditModel::ClearKeyword(const std::wstring& visible_text) { } bool AutocompleteEditModel::query_in_progress() const { - return popup_->query_in_progress(); + return !popup_->autocomplete_controller()->done(); } -const AutocompleteResult* AutocompleteEditModel::latest_result() const { - return popup_->latest_result(); +const AutocompleteResult& AutocompleteEditModel::result() const { + return popup_->autocomplete_controller()->result(); } void AutocompleteEditModel::OnSetFocus(bool control_down) { @@ -402,16 +396,21 @@ void AutocompleteEditModel::OnUpOrDownKeyPressed(int count) { // NOTE: This purposefully don't trigger any code that resets paste_state_. if (!popup_->is_open()) { - if (!popup_->query_in_progress()) { + if (popup_->autocomplete_controller()->done()) { // The popup is neither open nor working on a query already. So, start an // autocomplete query for the current text. This also sets // user_input_in_progress_ to true, which we want: if the user has started // to interact with the popup, changing the permanent_text_ shouldn't // change the displayed text. // Note: This does not force the popup to open immediately. + // TODO(pkasting): We should, in fact, force this particular query to open + // the popup immediately. if (!user_input_in_progress_) InternalSetUserText(permanent_text_); view_->UpdatePopup(); + } else { + // TODO(pkasting): The popup is working on a query but is not open. We + // should force it to open immediately. } } else { // The popup is open, so the user should be able to interact with it @@ -561,7 +560,7 @@ std::wstring AutocompleteEditModel::GetURLForCurrentText( PageTransition::Type* transition, bool* is_history_what_you_typed_match, std::wstring* alternate_nav_url) { - return (popup_->is_open() || popup_->query_in_progress()) ? + return (popup_->is_open() || !popup_->autocomplete_controller()->done()) ? popup_->URLsForCurrentSelection(transition, is_history_what_you_typed_match, alternate_nav_url) : diff --git a/chrome/browser/autocomplete/autocomplete_edit.h b/chrome/browser/autocomplete/autocomplete_edit.h index bdde105b..35b75b7 100644 --- a/chrome/browser/autocomplete/autocomplete_edit.h +++ b/chrome/browser/autocomplete/autocomplete_edit.h @@ -227,10 +227,10 @@ class AutocompleteEditModel { // AutomationProvider::AutocompleteEditIsQueryInProgress. bool query_in_progress() const; - // Returns the lastest autocomplete results. This logic should in the future + // Returns the current autocomplete result. This logic should in the future // live in AutocompleteController but resides here for now. This method is // used by AutomationProvider::AutocompleteEditGetMatches. - const AutocompleteResult* latest_result() const; + const AutocompleteResult& result() const; // Called when the view is gaining focus. |control_down| is whether the // control key is down (at the time we're gaining focus). diff --git a/chrome/browser/autocomplete/autocomplete_popup.cc b/chrome/browser/autocomplete/autocomplete_popup.cc index c04f50d..9dcc1b4 100644 --- a/chrome/browser/autocomplete/autocomplete_popup.cc +++ b/chrome/browser/autocomplete/autocomplete_popup.cc @@ -146,8 +146,6 @@ AutocompletePopupView::AutocompletePopupView(AutocompletePopupModel* model, } void AutocompletePopupView::InvalidateLine(size_t line) { - DCHECK(line < model_->result()->size()); - RECT rc; GetClientRect(&rc); rc.top = LineTopPixel(line); @@ -156,8 +154,9 @@ void AutocompletePopupView::InvalidateLine(size_t line) { } void AutocompletePopupView::UpdatePopupAppearance() { - if (model_->result()->empty()) { - // No results, close any existing popup. + const AutocompleteResult& result = model_->result(); + if (result.empty()) { + // No matches, close any existing popup. if (m_hWnd) { DestroyWindow(); m_hWnd = NULL; @@ -190,8 +189,7 @@ void AutocompletePopupView::UpdatePopupAppearance() { // bottom is and the rect has the height we need for all our entries, plus a // one-pixel border on top and bottom. rc.top = rc.bottom; - rc.bottom += - static_cast<int>(model_->result()->size()) * line_info_.line_height + 2; + rc.bottom += static_cast<int>(result.size()) * line_info_.line_height + 2; if (!m_hWnd) { // To prevent this window from being activated, we create an invisible @@ -297,7 +295,8 @@ void AutocompletePopupView::OnMouseMove(UINT keys, const CPoint& point) { } void AutocompletePopupView::OnPaint(HDC other_dc) { - DCHECK(!model_->result()->empty()); // Shouldn't be drawing an empty popup + const AutocompleteResult& result = model_->result(); + DCHECK(!result.empty()); // Shouldn't be drawing an empty popup. CPaintDC dc(m_hWnd); @@ -308,8 +307,8 @@ void AutocompletePopupView::OnPaint(HDC other_dc) { DrawBorder(rc, dc); bool all_descriptions_empty = true; - for (AutocompleteResult::const_iterator i(model_->result()->begin()); - i != model_->result()->end(); ++i) { + for (AutocompleteResult::const_iterator i(result.begin()); i != result.end(); + ++i) { if (!i->description.empty()) { all_descriptions_empty = false; break; @@ -329,14 +328,14 @@ void AutocompletePopupView::OnPaint(HDC other_dc) { else status = DrawLineInfo::NORMAL; DrawEntry(dc, rc, i, status, all_descriptions_empty, - model_->result()->match_at(i).starred); + result.match_at(i).starred); } } void AutocompletePopupView::OnButtonUp(const CPoint& point, WindowOpenDisposition disposition) { const size_t line = PixelToLine(point.y); - const AutocompleteMatch& match = model_->result()->match_at(line); + const AutocompleteMatch& match = model_->result().match_at(line); // OpenURL() may close the popup, which will clear the result set and, by // extension, |match| and its contents. So copy the relevant strings out to // make sure they stay alive until the call completes. @@ -348,14 +347,13 @@ void AutocompletePopupView::OnButtonUp(const CPoint& point, } int AutocompletePopupView::LineTopPixel(size_t line) const { - DCHECK(line <= model_->result()->size()); // The popup has a 1 px top border. return line_info_.line_height * static_cast<int>(line) + 1; } size_t AutocompletePopupView::PixelToLine(int y) const { const size_t line = std::max(y - 1, 0) / line_info_.line_height; - return std::min(line, model_->result()->size() - 1); + return std::min(line, model_->result().size() - 1); } // Draws a light border around the inside of the window with the given client @@ -588,7 +586,7 @@ void AutocompletePopupView::DrawEntry(HDC dc, // the HISTORY_SEARCH shortcut, the description section is eliminated, and // all the available width is used for the content section. int star_x; - const AutocompleteMatch& match = model_->result()->match_at(line); + const AutocompleteMatch& match = model_->result().match_at(line); if ((description_width < (line_info_.ave_char_width * 20)) || all_descriptions_empty || (match.type == AutocompleteMatch::HISTORY_SEARCH)) { @@ -714,15 +712,6 @@ COLORREF AutocompletePopupView::DrawLineInfo::AlphaBlend(COLORREF foreground, (GetBValue(background) * (0xff - alpha))) / 0xff); } -namespace { -// The amount of time we'll wait after a provider returns before updating, -// in order to coalesce results. -const int kPopupCoalesceMs = 100; - -// The maximum time we'll allow the popup to go without updating. -const int kPopupUpdateMaxDelayMs = 300; -}; - AutocompletePopupModel::AutocompletePopupModel( const ChromeFont& font, AutocompleteEditView* edit_view, @@ -730,12 +719,16 @@ AutocompletePopupModel::AutocompletePopupModel( Profile* profile) : view_(new AutocompletePopupView(this, font, edit_view)), edit_model_(edit_model), - controller_(new AutocompleteController(this, profile)), + controller_(new AutocompleteController(profile)), profile_(profile), - query_in_progress_(false), - update_pending_(false), hovered_line_(kNoMatch), - selected_line_(kNoMatch) { + selected_line_(kNoMatch), + inside_synchronous_query_(false) { + registrar_.Add(this, NOTIFY_AUTOCOMPLETE_CONTROLLER_RESULT_UPDATED, + Source<AutocompleteController>(controller_.get())); + registrar_.Add(this, + NOTIFY_AUTOCOMPLETE_CONTROLLER_SYNCHRONOUS_MATCHES_AVAILABLE, + Source<AutocompleteController>(controller_.get())); } AutocompletePopupModel::~AutocompletePopupModel() { @@ -756,56 +749,22 @@ void AutocompletePopupModel::StartAutocomplete( // The user is interacting with the edit, so stop tracking hover. SetHoveredLine(kNoMatch); - // See if we can avoid rerunning autocomplete when the query hasn't changed - // much. When the user presses or releases the ctrl key, the desired_tld - // changes, and when the user finishes an IME composition, inline autocomplete - // may no longer be prevented. In both these cases the text itself hasn't - // changed since the last query, and some providers can do much less work (and - // get results back more quickly). Taking advantage of this reduces flicker. - // If the popup isn't open, on the other hand, we threw the past results away, - // so no shortcuts are possible. - const bool minimal_changes = is_open() && (input_.text() == text); - input_ = AutocompleteInput(text, desired_tld, prevent_inline_autocomplete, - prefer_keyword); - - // If we're starting a brand new query, stop caring about any old query. - if (!minimal_changes && query_in_progress_) { - update_pending_ = false; - coalesce_timer_.Stop(); - } - - // Start the new query. manually_selected_match_.Clear(); - query_in_progress_ = !controller_->Start(input_, minimal_changes, false); - controller_->GetResult(&latest_result_); - - // If we're not ready to show results and the max update interval timer isn't - // already running, start it now. - if (query_in_progress_ && !max_delay_timer_.IsRunning()) - max_delay_timer_.Start(TimeDelta::FromMilliseconds(kPopupUpdateMaxDelayMs), - this, &AutocompletePopupModel::Run); - SetDefaultMatchAndUpdate(!query_in_progress_); + controller_->Start(text, desired_tld, prevent_inline_autocomplete, + prefer_keyword, false); } void AutocompletePopupModel::StopAutocomplete() { - // Close any old query. - StopQuery(); - - // Reset results. This will force the popup to close. - latest_result_.Reset(); - CommitLatestResults(true); - - // Clear input_ to make sure we don't try and use any of these results for the - // next query we receive. Strictly speaking this isn't necessary, since the - // popup isn't open, but it keeps our internal state consistent and serves as - // future-proofing in case the code in StartAutocomplete() changes. - input_.Clear(); + controller_->Stop(true); + SetHoveredLine(kNoMatch); + selected_line_ = kNoMatch; + view_->UpdatePopupAppearance(); } void AutocompletePopupModel::SetHoveredLine(size_t line) { const bool is_disabling = (line == kNoMatch); - DCHECK(is_disabling || (line < result_.size())); + DCHECK(is_disabling || (line < controller_->result().size())); if (line == hovered_line_) return; // Nothing to do @@ -827,14 +786,15 @@ void AutocompletePopupModel::SetHoveredLine(size_t line) { void AutocompletePopupModel::SetSelectedLine(size_t line, bool reset_to_default) { - DCHECK(line < result_.size()); - if (result_.empty()) + const AutocompleteResult& result = controller_->result(); + DCHECK(line < result.size()); + if (result.empty()) return; - // Cancel the query so the results don't change on the user. - StopQuery(); + // Cancel the query so the matches don't change on the user. + controller_->Stop(false); - const AutocompleteMatch& match = result_.match_at(line); + const AutocompleteMatch& match = result.match_at(line); if (reset_to_default) { manually_selected_match_.Clear(); } else { @@ -868,40 +828,42 @@ void AutocompletePopupModel::SetSelectedLine(size_t line, view_->UpdateWindow(); } +void AutocompletePopupModel::ResetToDefaultMatch() { + const AutocompleteResult& result = controller_->result(); + DCHECK(!result.empty()); + SetSelectedLine(result.default_match() - result.begin(), true); +} + std::wstring AutocompletePopupModel::URLsForCurrentSelection( PageTransition::Type* transition, bool* is_history_what_you_typed_match, std::wstring* alternate_nav_url) const { - // The popup may be out of date, and we always want the latest match. The - // most common case of this is when the popup is open, the user changes the - // contents of the edit, and then presses enter before any results have been - // displayed, but still wants to choose the would-be-default action. - // - // Can't call CommitLatestResults(), because - // latest_result_.default_match_index() may not match selected_line_, and - // we want to preserve the user's selection. - if (latest_result_.empty()) + // We need to use the result on the controller, because if the popup is open, + // the user changes the contents of the edit, and then presses enter before + // any results have been displayed, results_ will be nonempty but wrong. (In + // most other cases, the controller's results will match the popup's.) + // TODO(pkasting): If manually_selected_match_ moves to the controller, this + // can move to the edit. + if (controller_->result().empty()) return std::wstring(); - const AutocompleteResult* result; + const AutocompleteResult& result = controller_->result(); AutocompleteResult::const_iterator match; - if (update_pending_) { - // The default match on the latest result should be up-to-date. If the user - // changed the selection since that result was generated using the arrow - // keys, SetSelectedLine() will have force updated the popup. - result = &latest_result_; - match = result->default_match(); + if (!controller_->done()) { + // The user cannot have manually selected a match, or the query would have + // stopped. So the default match must be the desired selection. + match = result.default_match(); } else { - result = &result_; - DCHECK(selected_line_ < result_.size()); - match = result->begin() + selected_line_; + // The query isn't running, so the popup can't possibly be out of date. + DCHECK(selected_line_ < result.size()); + match = result.begin() + selected_line_; } if (transition) *transition = match->transition; if (is_history_what_you_typed_match) *is_history_what_you_typed_match = match->is_history_what_you_typed_match; if (alternate_nav_url && manually_selected_match_.empty()) - *alternate_nav_url = result->GetAlternateNavURL(input_, match); + *alternate_nav_url = result.GetAlternateNavURL(controller_->input(), match); return match->destination_url; } @@ -914,33 +876,31 @@ std::wstring AutocompletePopupModel::URLsForDefaultMatch( // We had better not already be doing anything, or this call will blow it // away. DCHECK(!is_open()); - DCHECK(!query_in_progress_); - - // Run the new query and get only the synchronously available results. - const AutocompleteInput input(text, desired_tld, true, false); - const bool done = controller_->Start(input, false, true); - DCHECK(done); - controller_->GetResult(&result_); - if (result_.empty()) + DCHECK(controller_->done()); + + // Run the new query and get only the synchronously available matches. + inside_synchronous_query_ = true; // Tell Observe() not to notify the edit or + // update our appearance. + controller_->Start(text, desired_tld, true, false, true); + inside_synchronous_query_ = false; + DCHECK(controller_->done()); + const AutocompleteResult& result = controller_->result(); + if (result.empty()) return std::wstring(); // Get the URLs for the default match. - const AutocompleteResult::const_iterator match = result_.default_match(); - const std::wstring url(match->destination_url); // Need to copy since we - // reset result_ below. + const AutocompleteResult::const_iterator match = result.default_match(); if (transition) *transition = match->transition; if (is_history_what_you_typed_match) *is_history_what_you_typed_match = match->is_history_what_you_typed_match; if (alternate_nav_url) - *alternate_nav_url = result_.GetAlternateNavURL(input, match); - result_.Reset(); - - return url; + *alternate_nav_url = result.GetAlternateNavURL(controller_->input(), match); + return match->destination_url; } bool AutocompletePopupModel::GetKeywordForMatch(const AutocompleteMatch& match, - std::wstring* keyword) { + std::wstring* keyword) const { // Assume we have no keyword until we find otherwise. keyword->clear(); @@ -972,11 +932,24 @@ bool AutocompletePopupModel::GetKeywordForMatch(const AutocompleteMatch& match, } AutocompleteLog* AutocompletePopupModel::GetAutocompleteLog() { - return new AutocompleteLog(input_.text(), selected_line_, 0, result_); + return new AutocompleteLog(controller_->input().text(), selected_line_, 0, + controller_->result()); } void AutocompletePopupModel::Move(int count) { - if (result_.empty()) + // TODO(pkasting): Temporary hack. If the query is running while the popup is + // open, we might be showing the results of the previous query still. Force + // the popup to display the latest results so the popup and the controller + // aren't out of sync. The better fix here is to roll the controller back to + // be in sync with what the popup is showing. + if (is_open() && !controller_->done()) { + Observe(NOTIFY_AUTOCOMPLETE_CONTROLLER_RESULT_UPDATED, + Source<AutocompleteController>(controller_.get()), + NotificationService::NoDetails()); + } + + const AutocompleteResult& result = controller_->result(); + if (result.empty()) return; // The user is using the keyboard to change the selection, so stop tracking @@ -986,7 +959,7 @@ void AutocompletePopupModel::Move(int count) { // Clamp the new line to [0, result_.count() - 1]. const size_t new_line = selected_line_ + count; SetSelectedLine((((count < 0) && (new_line >= selected_line_)) ? - 0 : std::min(new_line, result_.size() - 1)), false); + 0 : std::min(new_line, result.size() - 1)), false); } void AutocompletePopupModel::TryDeletingCurrentItem() { @@ -995,111 +968,76 @@ void AutocompletePopupModel::TryDeletingCurrentItem() { // yet visible" one. if (selected_line_ == kNoMatch) return; - const AutocompleteMatch& match = result_.match_at(selected_line_); + const AutocompleteMatch& match = + controller_->result().match_at(selected_line_); if (match.deletable) { - query_in_progress_ = true; - size_t selected_line = selected_line_; - match.provider->DeleteMatch(match); // This will synchronously call back - // to OnAutocompleteUpdate() - CommitLatestResults(false); - if (!result_.empty()) { + const size_t selected_line = selected_line_; + controller_->DeleteMatch(match); // This will synchronously notify us that + // the results have changed. + const AutocompleteResult& result = controller_->result(); + if (!result.empty()) { // Move the selection to the next choice after the deleted one. - SetSelectedLine(std::min(result_.size() - 1, selected_line), false); + // TODO(pkasting): Eventually the controller should take care of this + // before notifying us, reducing flicker. At that point the check for + // deletability can move there too. + SetSelectedLine(std::min(result.size() - 1, selected_line), false); } } } -void AutocompletePopupModel::OnAutocompleteUpdate(bool updated_result, - bool query_complete) { - DCHECK(query_in_progress_); - if (updated_result) - controller_->GetResult(&latest_result_); - query_in_progress_ = !query_complete; - - SetDefaultMatchAndUpdate(query_complete); -} - -void AutocompletePopupModel::Run() { - CommitLatestResults(false); -} - -void AutocompletePopupModel::StopQuery() { - if (query_in_progress_) { - controller_->Stop(); - query_in_progress_ = false; - update_pending_ = false; - latest_result_.CopyFrom(result_); // Not strictly necessary, but keeps - // internal state consistent. - } -} - -void AutocompletePopupModel::SetDefaultMatchAndUpdate(bool immediately) { - if (immediately) { - CommitLatestResults(true); - } else if (!update_pending_) { - // Coalesce the results for the next kPopupCoalesceMs milliseconds. - update_pending_ = true; - coalesce_timer_.Stop(); - coalesce_timer_.Start(TimeDelta::FromMilliseconds(kPopupCoalesceMs), this, - &AutocompletePopupModel::Run); - } - - // Update the edit with the possibly new data for this match. - // NOTE: This must be done after the code above, so that our internal state - // will be consistent when the edit calls back to URLsForCurrentSelection(). - std::wstring inline_autocomplete_text; - std::wstring keyword; - bool is_keyword_hint = false; - bool can_show_search_hint = true; - const AutocompleteResult::const_iterator match( - latest_result_.default_match()); - if (match != latest_result_.end()) { - if ((match->inline_autocomplete_offset != std::wstring::npos) && - (match->inline_autocomplete_offset < match->fill_into_edit.length())) { - inline_autocomplete_text = - match->fill_into_edit.substr(match->inline_autocomplete_offset); - } - // Warm up DNS Prefetch Cache. - chrome_browser_net::DnsPrefetchUrlString(match->destination_url); - // We could prefetch the alternate nav URL, if any, but because there can be - // many of these as a user types an initial series of characters, the OS DNS - // cache could suffer eviction problems for minimal gain. - - is_keyword_hint = GetKeywordForMatch(*match, &keyword); - can_show_search_hint = (match->type == AutocompleteMatch::SEARCH); - } - edit_model_->OnPopupDataChanged(inline_autocomplete_text, false, keyword, - is_keyword_hint, can_show_search_hint); -} - -void AutocompletePopupModel::CommitLatestResults(bool force) { - if (!force && !update_pending_) +void AutocompletePopupModel::Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details) { + if (inside_synchronous_query_) return; - update_pending_ = false; - - // If we're going to trim the window size to no longer include the hovered - // line, turn hover off first. We need to do this before changing result_ - // since SetHoveredLine() should be able to trust that the old and new hovered - // lines are valid. - // - // Practically, this only currently happens when we're closing the window by - // setting latest_result_ to an empty list. - if ((hovered_line_ != kNoMatch) && (latest_result_.size() <= hovered_line_)) - SetHoveredLine(kNoMatch); - - result_.CopyFrom(latest_result_); - selected_line_ = (result_.default_match() == result_.end()) ? - kNoMatch : (result_.default_match() - result_.begin()); - - view_->UpdatePopupAppearance(); + const AutocompleteResult& result = controller_->result(); + switch (type) { + case NOTIFY_AUTOCOMPLETE_CONTROLLER_RESULT_UPDATED: { + selected_line_ = (result.default_match() == result.end()) ? + kNoMatch : (result.default_match() - result.begin()); + // If we're going to trim the window size to no longer include the hovered + // line, turn hover off. Practically, this shouldn't happen, but it + // doesn't hurt to be defensive. + if ((hovered_line_ != kNoMatch) && (result.size() <= hovered_line_)) + SetHoveredLine(kNoMatch); + + view_->UpdatePopupAppearance(); + } + // FALL THROUGH + + case NOTIFY_AUTOCOMPLETE_CONTROLLER_SYNCHRONOUS_MATCHES_AVAILABLE: { + // Update the edit with the possibly new data for this match. + // NOTE: This must be done after the code above, so that our internal + // state will be consistent when the edit calls back to + // URLsForCurrentSelection(). + std::wstring inline_autocomplete_text; + std::wstring keyword; + bool is_keyword_hint = false; + bool can_show_search_hint = true; + const AutocompleteResult::const_iterator match(result.default_match()); + if (match != result.end()) { + if ((match->inline_autocomplete_offset != std::wstring::npos) && + (match->inline_autocomplete_offset < + match->fill_into_edit.length())) { + inline_autocomplete_text = + match->fill_into_edit.substr(match->inline_autocomplete_offset); + } + // Warm up DNS Prefetch Cache. + chrome_browser_net::DnsPrefetchUrlString(match->destination_url); + // We could prefetch the alternate nav URL, if any, but because there + // can be many of these as a user types an initial series of characters, + // the OS DNS cache could suffer eviction problems for minimal gain. + + is_keyword_hint = GetKeywordForMatch(*match, &keyword); + can_show_search_hint = (match->type == AutocompleteMatch::SEARCH); + } + edit_model_->OnPopupDataChanged(inline_autocomplete_text, false, keyword, + is_keyword_hint, can_show_search_hint); + return; + } - // The max update interval timer either needs to be reset (if more updates - // are to come) or stopped (when we're done with the query). The coalesce - // timer should always just be stopped. - coalesce_timer_.Stop(); - if (query_in_progress_) - max_delay_timer_.Reset(); - else - max_delay_timer_.Stop(); -} + default: + NOTREACHED(); + } +}
\ No newline at end of file diff --git a/chrome/browser/autocomplete/autocomplete_popup.h b/chrome/browser/autocomplete/autocomplete_popup.h index 9d01f84..593f169 100644 --- a/chrome/browser/autocomplete/autocomplete_popup.h +++ b/chrome/browser/autocomplete/autocomplete_popup.h @@ -10,11 +10,10 @@ #include <atlcrack.h> #include <atlmisc.h> -#include "base/task.h" -#include "base/timer.h" #include "base/win_util.h" #include "chrome/browser/autocomplete/autocomplete.h" #include "chrome/common/gfx/chrome_font.h" +#include "chrome/common/notification_registrar.h" #include "chrome/views/view.h" class AutocompleteEditModel; @@ -61,8 +60,8 @@ class AutocompletePopupView // Invalidates one line of the autocomplete popup. void InvalidateLine(size_t line); - // Redraws the popup window to match any changes in result_; this may mean - // opening or closing the window. + // Redraws the popup window to match any changes in the result set; this may + // mean opening or closing the window. void UpdatePopupAppearance(); // Called by the model when hover is enabled or disabled. @@ -203,7 +202,7 @@ class AutocompletePopupView DISALLOW_COPY_AND_ASSIGN(AutocompletePopupView); }; -class AutocompletePopupModel : public ACControllerListener, public Task { +class AutocompletePopupModel : public NotificationObserver { public: AutocompletePopupModel(const ChromeFont& font, AutocompleteEditView* edit_view, @@ -214,19 +213,8 @@ class AutocompletePopupModel : public ACControllerListener, public Task { // Invoked when the profile has changed. void SetProfile(Profile* profile); - // Gets autocomplete results for the given text. If there are results, opens - // the popup if necessary and fills it with the new data. Otherwise, closes - // the popup if necessary. - // - // |prevent_inline_autocomplete| is true if the generated result set should - // not require inline autocomplete for the default match. This is difficult - // to explain in the abstract; the practical use case is that after the user - // deletes text in the edit, the HistoryURLProvider should make sure not to - // promote a match requiring inline autocomplete too highly. - // - // |prefer_keyword| should be true when the keyword UI is onscreen; this will - // bias the autocomplete results toward the keyword provider when the input - // string is a bare keyword. + // Starts a new query running. These parameters are passed through to the + // autocomplete controller; see comments there. void StartAutocomplete(const std::wstring& text, const std::wstring& desired_tld, bool prevent_inline_autocomplete, @@ -243,15 +231,8 @@ class AutocompletePopupModel : public ACControllerListener, public Task { return controller_.get(); } - // Returns true if no autocomplete query is currently running. - bool query_in_progress() const { return query_in_progress_; } - - const AutocompleteResult* result() const { - return &result_; - } - - const AutocompleteResult* latest_result() const { - return &latest_result_; + const AutocompleteResult& result() const { + return controller_->result(); } size_t hovered_line() const { @@ -278,13 +259,11 @@ class AutocompletePopupModel : public ACControllerListener, public Task { // Called when the user hits escape after arrowing around the popup. This // will change the selected line back to the default match and redraw. - void ResetToDefaultMatch() { - SetSelectedLine(result_.default_match() - result_.begin(), true); - } + void ResetToDefaultMatch(); // Returns the URL for the selected match. If an update is in progress, - // "selected" means "default in the latest results". If there are no - // results, returns the empty string. + // "selected" means "default in the latest matches". If there are no + // matches, returns the empty string. // // If |transition_type| is non-NULL, it will be set to the appropriate // transition type for the selected entry (TYPED or GENERATED). @@ -302,9 +281,9 @@ class AutocompletePopupModel : public ACControllerListener, public Task { // This is sort of a hybrid between StartAutocomplete() and // URLForCurrentSelection(). When the popup isn't open and the user hits - // enter, we want to get the default result for the user's input immediately, + // enter, we want to get the default match for the user's input immediately, // and not open the popup, continue running autocomplete, etc. Therefore, - // this does a query for only the synchronously available results for the + // this does a query for only the synchronously available matches for the // provided input parameters, sets |transition|, // |is_history_what_you_typed_match|, and |alternate_nav_url| (if applicable) // based on the default match, and returns its url. |transition|, @@ -325,7 +304,7 @@ class AutocompletePopupModel : public ACControllerListener, public Task { // possibly to the empty string], and you cannot have both a selected keyword // and a keyword hint simultaneously.) bool GetKeywordForMatch(const AutocompleteMatch& match, - std::wstring* keyword); + std::wstring* keyword) const; // Returns a pointer to a heap-allocated AutocompleteLog containing the // current input text, selected match, and result set. The caller is @@ -343,71 +322,26 @@ class AutocompletePopupModel : public ACControllerListener, public Task { // can be removed from history, and if so, remove it and update the popup. void TryDeletingCurrentItem(); - // ACControllerListener - called when more autocomplete data is available or - // when the query is complete. - // - // When the input for the current query has a provider affinity, we try to - // keep the current result set's default match as the new default match. - virtual void OnAutocompleteUpdate(bool updated_result, bool query_complete); - - // Task - called when either timer fires. Calls CommitLatestResults(). - virtual void Run(); - // The token value for selected_line_, hover_line_ and functions dealing with // a "line number" that indicates "no line". static const size_t kNoMatch = -1; private: - // Stops an existing query but doesn't close the popup. - void StopQuery(); - - // Sets the correct default match in latest_result_, then updates the popup - // appearance to match. If |immediately| is true this update happens - // synchronously; otherwise, it's deferred until the next scheduled update. - void SetDefaultMatchAndUpdate(bool immediately); - - // If an update is pending or |force| is true, immediately updates result_ to - // match latest_result_, and calls UpdatePopupAppearance() to reflect those - // changes back to the user. - void CommitLatestResults(bool force); + // NotificationObserver + virtual void Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details); scoped_ptr<AutocompletePopupView> view_; AutocompleteEditModel* edit_model_; scoped_ptr<AutocompleteController> controller_; + NotificationRegistrar registrar_; + // Profile for current tab. Profile* profile_; - // The input for the current query. - AutocompleteInput input_; - - // Data from the autocomplete query. - AutocompleteResult result_; - - // True if an autocomplete query is currently running. - bool query_in_progress_; - - // The latest result available from the autocomplete service. This may be - // different than result_ if we've gotten results from our providers that we - // haven't yet shown the user. If more results may be coming, we'll wait to - // display these in hopes of minimizing flicker; see coalesce_timer_. - AutocompleteResult latest_result_; - - // True when there are newer results in latest_result_ than in result_ and - // the popup has not been updated to show them. - bool update_pending_; - - // Timer that tracks how long it's been since the last provider update we - // received. Instead of displaying each update immediately, we batch updates - // into groups, which reduces flicker. - base::OneShotTimer<AutocompletePopupModel> coalesce_timer_; - - // Timer that tracks how long it's been since the last time we updated the - // onscreen results. This is used to ensure that the popup is somewhat - // responsive even when the user types continuously. - base::RepeatingTimer<AutocompletePopupModel> max_delay_timer_; - // The line that's currently hovered. If we're not drawing a hover rect, // this will be kNoMatch, even if the cursor is over the popup contents. size_t hovered_line_; @@ -419,6 +353,10 @@ class AutocompletePopupModel : public ACControllerListener, public Task { // The match the user has manually chosen, if any. AutocompleteResult::Selection manually_selected_match_; + // A hack for URLsForDefaultMatch() that makes the code in Observe() do + // nothing. + bool inside_synchronous_query_; + DISALLOW_COPY_AND_ASSIGN(AutocompletePopupModel); }; diff --git a/chrome/browser/autocomplete/autocomplete_unittest.cc b/chrome/browser/autocomplete/autocomplete_unittest.cc index af96555..27d4ccb 100644 --- a/chrome/browser/autocomplete/autocomplete_unittest.cc +++ b/chrome/browser/autocomplete/autocomplete_unittest.cc @@ -5,6 +5,7 @@ #include "base/message_loop.h" #include "base/ref_counted.h" #include "chrome/browser/autocomplete/autocomplete.h" +#include "chrome/common/notification_registrar.h" #include "testing/gtest/include/gtest/gtest.h" // identifiers for known autocomplete providers @@ -26,8 +27,7 @@ class TestProvider : public AutocompleteProvider { } virtual void Start(const AutocompleteInput& input, - bool minimal_changes, - bool synchronous_only); + bool minimal_changes); void set_listener(ACProviderListener* listener) { listener_ = listener; @@ -43,8 +43,7 @@ class TestProvider : public AutocompleteProvider { }; void TestProvider::Start(const AutocompleteInput& input, - bool minimal_changes, - bool synchronous_only) { + bool minimal_changes) { if (minimal_changes) return; @@ -53,7 +52,7 @@ void TestProvider::Start(const AutocompleteInput& input, // Generate one result synchronously, the rest later. AddResults(0, 1); - if (!synchronous_only) { + if (!input.synchronous_only()) { done_ = false; MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod( this, &TestProvider::Run)); @@ -89,11 +88,7 @@ void TestProvider::AddResults(int start_at, int num) { } class AutocompleteProviderTest : public testing::Test, - public ACControllerListener { - public: - // ACControllerListener - virtual void OnAutocompleteUpdate(bool updated_result, bool query_complete); - + public NotificationObserver { protected: // testing::Test virtual void SetUp(); @@ -110,11 +105,22 @@ class AutocompleteProviderTest : public testing::Test, AutocompleteResult result_; private: + // NotificationObserver + virtual void Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details); + MessageLoopForUI message_loop_; scoped_ptr<AutocompleteController> controller_; + NotificationRegistrar registrar_; }; void AutocompleteProviderTest::SetUp() { + registrar_.Add(this, NOTIFY_AUTOCOMPLETE_CONTROLLER_RESULT_UPDATED, + NotificationService::AllSources()); + registrar_.Add(this, + NOTIFY_AUTOCOMPLETE_CONTROLLER_SYNCHRONOUS_MATCHES_AVAILABLE, + NotificationService::AllSources()); ResetController(false); } @@ -134,30 +140,30 @@ void AutocompleteProviderTest::ResetController(bool same_destinations) { providers_.push_back(providerB); // Reset the controller to contain our new providers. - AutocompleteController* controller = - new AutocompleteController(this, providers_); + AutocompleteController* controller = new AutocompleteController(providers_); controller_.reset(controller); providerA->set_listener(controller); providerB->set_listener(controller); } -void AutocompleteProviderTest::OnAutocompleteUpdate(bool updated_result, - bool query_complete) { - controller_->GetResult(&result_); - if (query_complete) - MessageLoop::current()->Quit(); -} - void AutocompleteProviderTest::RunTest() { result_.Reset(); - const AutocompleteInput input(L"a", std::wstring(), true, false); - EXPECT_FALSE(controller_->Start(input, false, false)); + controller_->Start(L"a", std::wstring(), true, false, false); // The message loop will terminate when all autocomplete input has been // collected. MessageLoop::current()->Run(); } +void AutocompleteProviderTest::Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details) { + if (controller_->done()) { + result_.CopyFrom(controller_->result()); + MessageLoop::current()->Quit(); + } +} + } // namespace std::ostream& operator<<(std::ostream& os, @@ -228,7 +234,8 @@ TEST(AutocompleteTest, InputType) { }; for (int i = 0; i < arraysize(input_cases); ++i) { - AutocompleteInput input(input_cases[i].input, std::wstring(), true, false); + AutocompleteInput input(input_cases[i].input, std::wstring(), true, false, + false); EXPECT_EQ(input_cases[i].type, input.type()) << "Input: " << input_cases[i].input; } diff --git a/chrome/browser/autocomplete/history_contents_provider.cc b/chrome/browser/autocomplete/history_contents_provider.cc index d8c91e8..c1ef435c 100644 --- a/chrome/browser/autocomplete/history_contents_provider.cc +++ b/chrome/browser/autocomplete/history_contents_provider.cc @@ -38,11 +38,11 @@ bool CompareMatchRelevance(const MatchReference& a, const MatchReference& b) { using history::HistoryDatabase; void HistoryContentsProvider::Start(const AutocompleteInput& input, - bool minimal_changes, - bool synchronous_only) { + bool minimal_changes) { matches_.clear(); if (input.text().empty() || (input.type() == AutocompleteInput::INVALID) || + !profile_ || // The history service or bookmark bar model must exist. !(profile_->GetHistoryService(Profile::EXPLICIT_ACCESS) || profile_->GetBookmarkModel())) { @@ -80,7 +80,7 @@ void HistoryContentsProvider::Start(const AutocompleteInput& input, // allowed to keep running it, do so, and when it finishes, its results will // get marked up for this new input. In synchronous_only mode, cancel the // history query. - if (synchronous_only) { + if (input.synchronous_only()) { done_ = true; request_consumer_.CancelAllRequests(); } @@ -100,7 +100,7 @@ void HistoryContentsProvider::Start(const AutocompleteInput& input, // Convert the bookmark results. ConvertResults(); - if (!synchronous_only) { + if (!input.synchronous_only()) { HistoryService* history = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS); if (history) { diff --git a/chrome/browser/autocomplete/history_contents_provider.h b/chrome/browser/autocomplete/history_contents_provider.h index f824480..8c4f62c 100644 --- a/chrome/browser/autocomplete/history_contents_provider.h +++ b/chrome/browser/autocomplete/history_contents_provider.h @@ -21,14 +21,12 @@ class HistoryContentsProvider : public AutocompleteProvider { HistoryContentsProvider(ACProviderListener* listener, Profile* profile) : AutocompleteProvider(listener, profile, "HistoryContents"), have_results_(false) { - DCHECK(profile); } // As necessary asks the history service for the relevant results. When // done SetResults is invoked. virtual void Start(const AutocompleteInput& input, - bool minimal_changes, - bool synchronous_only); + bool minimal_changes); virtual void Stop(); diff --git a/chrome/browser/autocomplete/history_contents_provider_unittest.cc b/chrome/browser/autocomplete/history_contents_provider_unittest.cc index dabdcfa..9777c71 100644 --- a/chrome/browser/autocomplete/history_contents_provider_unittest.cc +++ b/chrome/browser/autocomplete/history_contents_provider_unittest.cc @@ -34,13 +34,12 @@ class HistoryContentsProviderTest : public testing::Test, public: void RunQuery(const AutocompleteInput& input, - bool minimal_changes, - bool synchronous_only) { - provider_->Start(input, minimal_changes, synchronous_only); + bool minimal_changes) { + provider_->Start(input, minimal_changes); // When we're waiting for asynchronous messages, we have to spin the message // loop. This will be exited in the OnProviderUpdate function when complete. - if (!synchronous_only) + if (!input.synchronous_only()) MessageLoop::current()->Run(); } @@ -101,8 +100,8 @@ class HistoryContentsProviderTest : public testing::Test, } // namespace TEST_F(HistoryContentsProviderTest, Body) { - AutocompleteInput input(L"FOO", std::wstring(), true, false); - RunQuery(input, false, false); + AutocompleteInput input(L"FOO", std::wstring(), true, false, false); + RunQuery(input, false); // The results should be the first two pages, in decreasing order. const ACMatches& m = matches(); @@ -114,8 +113,8 @@ TEST_F(HistoryContentsProviderTest, Body) { } TEST_F(HistoryContentsProviderTest, Title) { - AutocompleteInput input(L"PAGEONE", std::wstring(), true, false); - RunQuery(input, false, false); + AutocompleteInput input(L"PAGEONE", std::wstring(), true, false, false); + RunQuery(input, false); // The results should be the first two pages. const ACMatches& m = matches(); @@ -128,22 +127,22 @@ TEST_F(HistoryContentsProviderTest, Title) { // The "minimal changes" flag should mean that we don't re-query the DB. TEST_F(HistoryContentsProviderTest, MinimalChanges) { - AutocompleteInput input(L"PAGEONE", std::wstring(), true, false); - // A minimal changes request when there have been no real queries should // give us no results. - RunQuery(input, true, true); + AutocompleteInput sync_input(L"PAGEONE", std::wstring(), true, false, true); + RunQuery(sync_input, true); const ACMatches& m1 = matches(); EXPECT_EQ(0, m1.size()); // Now do a "regular" query to get the results. - RunQuery(input, false, false); + AutocompleteInput async_input(L"PAGEONE", std::wstring(), true, false, false); + RunQuery(async_input, false); const ACMatches& m2 = matches(); EXPECT_EQ(2, m2.size()); // Now do a minimal one where we want synchronous results, and the results // should still be there. - RunQuery(input, true, true); + RunQuery(sync_input, true); const ACMatches& m3 = matches(); EXPECT_EQ(2, m3.size()); } @@ -157,10 +156,9 @@ TEST_F(HistoryContentsProviderTest, Bookmarks) { GURL bookmark_url("http://www.google.com/4"); profile()->GetBookmarkModel()->SetURLStarred(bookmark_url, L"bar", true); - AutocompleteInput input(L"bar", std::wstring(), true, false); - // Ask for synchronous. This should only get the bookmark. - RunQuery(input, false, true); + AutocompleteInput sync_input(L"bar", std::wstring(), true, false, true); + RunQuery(sync_input, false); const ACMatches& m1 = matches(); ASSERT_EQ(1, m1.size()); EXPECT_EQ(bookmark_url.spec(), WideToUTF8(m1[0].destination_url)); @@ -168,7 +166,8 @@ TEST_F(HistoryContentsProviderTest, Bookmarks) { EXPECT_TRUE(m1[0].starred); // Ask for async. We should get the bookmark immediately. - provider()->Start(input, false, false); + AutocompleteInput async_input(L"bar", std::wstring(), true, false, false); + provider()->Start(async_input, false); const ACMatches& m2 = matches(); ASSERT_EQ(1, m2.size()); EXPECT_EQ(bookmark_url.spec(), WideToUTF8(m2[0].destination_url)); diff --git a/chrome/browser/autocomplete/history_url_provider.cc b/chrome/browser/autocomplete/history_url_provider.cc index 3f5a7ff..9a25e90 100644 --- a/chrome/browser/autocomplete/history_url_provider.cc +++ b/chrome/browser/autocomplete/history_url_provider.cc @@ -37,8 +37,7 @@ HistoryURLProviderParams::HistoryURLProviderParams( } void HistoryURLProvider::Start(const AutocompleteInput& input, - bool minimal_changes, - bool synchronous_only) { + bool minimal_changes) { // NOTE: We could try hard to do less work in the |minimal_changes| case // here; some clever caching would let us reuse the raw matches from the // history DB without re-querying. However, we'd still have to go back to @@ -51,7 +50,7 @@ void HistoryURLProvider::Start(const AutocompleteInput& input, // Cancel any in-progress query. Stop(); - RunAutocompletePasses(input, true, !synchronous_only); + RunAutocompletePasses(input, true); } void HistoryURLProvider::Stop() { @@ -99,7 +98,7 @@ void HistoryURLProvider::DeleteMatch(const AutocompleteMatch& match) { // out from under us on the other thread after we set params_->cancel here. AutocompleteInput input(params_->input); params_->cancel = true; - RunAutocompletePasses(input, false, true); + RunAutocompletePasses(input, false); } } @@ -577,8 +576,7 @@ void HistoryURLProvider::EnsureMatchPresent( } void HistoryURLProvider::RunAutocompletePasses(const AutocompleteInput& input, - bool fixup_input_and_run_pass_1, - bool run_pass_2) { + bool fixup_input_and_run_pass_1) { matches_.clear(); if ((input.type() != AutocompleteInput::UNKNOWN) && @@ -650,7 +648,7 @@ void HistoryURLProvider::RunAutocompletePasses(const AutocompleteInput& input, // Pass 2: Ask the history service to call us back on the history thread, // where we can read the full on-disk DB. - if (run_pass_2) { + if (!input.synchronous_only()) { done_ = false; params_ = params.release(); // This object will be destroyed in // QueryComplete() once we're done with it. diff --git a/chrome/browser/autocomplete/history_url_provider.h b/chrome/browser/autocomplete/history_url_provider.h index 3681a0a..6261a47 100644 --- a/chrome/browser/autocomplete/history_url_provider.h +++ b/chrome/browser/autocomplete/history_url_provider.h @@ -150,8 +150,7 @@ class HistoryURLProvider : public AutocompleteProvider { // AutocompleteProvider virtual void Start(const AutocompleteInput& input, - bool minimal_changes, - bool synchronous_only); + bool minimal_changes); virtual void Stop(); virtual void DeleteMatch(const AutocompleteMatch& match); @@ -313,8 +312,7 @@ class HistoryURLProvider : public AutocompleteProvider { // Helper function that actually launches the two autocomplete passes. void RunAutocompletePasses(const AutocompleteInput& input, - bool fixup_input_and_run_pass_1, - bool run_pass_2); + bool fixup_input_and_run_pass_1); // Returns the best prefix that begins |text|. "Best" means "greatest number // of components". This may return NULL if no prefix begins |text|. diff --git a/chrome/browser/autocomplete/history_url_provider_unittest.cc b/chrome/browser/autocomplete/history_url_provider_unittest.cc index 2b863db..0f5fc5d 100644 --- a/chrome/browser/autocomplete/history_url_provider_unittest.cc +++ b/chrome/browser/autocomplete/history_url_provider_unittest.cc @@ -156,8 +156,8 @@ void HistoryURLProviderTest::RunTest(const std::wstring text, const std::wstring* expected_urls, int num_results) { AutocompleteInput input(text, desired_tld, prevent_inline_autocomplete, - false); - autocomplete_->Start(input, false, false); + false, false); + autocomplete_->Start(input, false); if (!autocomplete_->done()) MessageLoop::current()->Run(); diff --git a/chrome/browser/autocomplete/keyword_provider.cc b/chrome/browser/autocomplete/keyword_provider.cc index f389a4a..4674d85 100644 --- a/chrome/browser/autocomplete/keyword_provider.cc +++ b/chrome/browser/autocomplete/keyword_provider.cc @@ -60,8 +60,7 @@ class KeywordProvider::CompareQuality { }; void KeywordProvider::Start(const AutocompleteInput& input, - bool minimal_changes, - bool synchronous_only) { + bool minimal_changes) { matches_.clear(); if ((input.type() == AutocompleteInput::INVALID) || diff --git a/chrome/browser/autocomplete/keyword_provider.h b/chrome/browser/autocomplete/keyword_provider.h index b39b90f..dab7ad3 100644 --- a/chrome/browser/autocomplete/keyword_provider.h +++ b/chrome/browser/autocomplete/keyword_provider.h @@ -62,8 +62,7 @@ class KeywordProvider : public AutocompleteProvider { // AutocompleteProvider virtual void Start(const AutocompleteInput& input, - bool minimal_changes, - bool synchronous_only); + bool minimal_changes); private: // Helper functor for Start(), for sorting keyword matches by quality. diff --git a/chrome/browser/autocomplete/keyword_provider_unittest.cc b/chrome/browser/autocomplete/keyword_provider_unittest.cc index f4b50c6..aceab5f 100644 --- a/chrome/browser/autocomplete/keyword_provider_unittest.cc +++ b/chrome/browser/autocomplete/keyword_provider_unittest.cc @@ -59,8 +59,8 @@ void KeywordProviderTest::RunTest( ACMatches matches; for (int i = 0; i < num_cases; ++i) { AutocompleteInput input(keyword_cases[i].input, std::wstring(), true, - false); - kw_provider_->Start(input, false, false); + false, false); + kw_provider_->Start(input, false); EXPECT_TRUE(kw_provider_->done()); matches = kw_provider_->matches(); EXPECT_EQ(keyword_cases[i].num_results, matches.size()) << diff --git a/chrome/browser/autocomplete/search_provider.cc b/chrome/browser/autocomplete/search_provider.cc index 71b1ef5..c631ec2 100644 --- a/chrome/browser/autocomplete/search_provider.cc +++ b/chrome/browser/autocomplete/search_provider.cc @@ -22,8 +22,7 @@ const int SearchProvider::kQueryDelayMs = 200; void SearchProvider::Start(const AutocompleteInput& input, - bool minimal_changes, - bool synchronous_only) { + bool minimal_changes) { matches_.clear(); // Can't return search/suggest results for bogus input or if there is no @@ -75,8 +74,8 @@ void SearchProvider::Start(const AutocompleteInput& input, input_ = input; - StartOrStopHistoryQuery(minimal_changes, synchronous_only); - StartOrStopSuggestQuery(minimal_changes, synchronous_only); + StartOrStopHistoryQuery(minimal_changes); + StartOrStopSuggestQuery(minimal_changes); ConvertResultsToAutocompleteMatches(); } @@ -137,20 +136,19 @@ void SearchProvider::OnURLFetchComplete(const URLFetcher* source, listener_->OnProviderUpdate(!suggest_results_.empty()); } -void SearchProvider::StartOrStopHistoryQuery(bool minimal_changes, - bool synchronous_only) { +void SearchProvider::StartOrStopHistoryQuery(bool minimal_changes) { // For the minimal_changes case, if we finished the previous query and still // have its results, or are allowed to keep running it, just do that, rather // than starting a new query. if (minimal_changes && - (have_history_results_ || (!done_ && !synchronous_only))) + (have_history_results_ || (!done_ && !input_.synchronous_only()))) return; // We can't keep running any previous query, so halt it. StopHistory(); // We can't start a new query if we're only allowed synchronous results. - if (synchronous_only) + if (input_.synchronous_only()) return; // Start the history query. @@ -163,8 +161,7 @@ void SearchProvider::StartOrStopHistoryQuery(bool minimal_changes, history_request_pending_ = true; } -void SearchProvider::StartOrStopSuggestQuery(bool minimal_changes, - bool synchronous_only) { +void SearchProvider::StartOrStopSuggestQuery(bool minimal_changes) { if (!IsQuerySuitableForSuggest()) { StopSuggest(); return; @@ -174,14 +171,14 @@ void SearchProvider::StartOrStopSuggestQuery(bool minimal_changes, // have its results, or are allowed to keep running it, just do that, rather // than starting a new query. if (minimal_changes && - (have_suggest_results_ || (!done_ && !synchronous_only))) + (have_suggest_results_ || (!done_ && !input_.synchronous_only()))) return; // We can't keep running any previous query, so halt it. StopSuggest(); // We can't start a new query if we're only allowed synchronous results. - if (synchronous_only) + if (input_.synchronous_only()) return; // Kick off a timer that will start the URL fetch if it completes before diff --git a/chrome/browser/autocomplete/search_provider.h b/chrome/browser/autocomplete/search_provider.h index 57a723d..9e7fde1 100644 --- a/chrome/browser/autocomplete/search_provider.h +++ b/chrome/browser/autocomplete/search_provider.h @@ -48,8 +48,7 @@ class SearchProvider : public AutocompleteProvider, // AutocompleteProvider virtual void Start(const AutocompleteInput& input, - bool minimal_changes, - bool synchronous_only); + bool minimal_changes); virtual void Stop(); // URLFetcher::Delegate @@ -85,8 +84,8 @@ class SearchProvider : public AutocompleteProvider, // Determines whether an asynchronous subcomponent query should run for the // current input. If so, starts it if necessary; otherwise stops it. // NOTE: These functions do not update |done_|. Callers must do so. - void StartOrStopHistoryQuery(bool minimal_changes, bool synchronous_only); - void StartOrStopSuggestQuery(bool minimal_changes, bool synchronous_only); + void StartOrStopHistoryQuery(bool minimal_changes); + 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 |