summaryrefslogtreecommitdiffstats
path: root/chrome/browser/autocomplete
diff options
context:
space:
mode:
authorpkasting@chromium.org <pkasting@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2008-10-09 18:21:27 +0000
committerpkasting@chromium.org <pkasting@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2008-10-09 18:21:27 +0000
commit8deeb95696562494db58140a46fbe06432f39d57 (patch)
treee74fed0de316dd2bc97805b0ba2a942fb8d53aff /chrome/browser/autocomplete
parent3b2a95c36e98d35b417466054349d2d5308c2af3 (diff)
downloadchromium_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')
-rw-r--r--chrome/browser/autocomplete/autocomplete.cc207
-rw-r--r--chrome/browser/autocomplete/autocomplete.h174
-rw-r--r--chrome/browser/autocomplete/autocomplete_edit.cc35
-rw-r--r--chrome/browser/autocomplete/autocomplete_edit.h4
-rw-r--r--chrome/browser/autocomplete/autocomplete_popup.cc360
-rw-r--r--chrome/browser/autocomplete/autocomplete_popup.h110
-rw-r--r--chrome/browser/autocomplete/autocomplete_unittest.cc51
-rw-r--r--chrome/browser/autocomplete/history_contents_provider.cc8
-rw-r--r--chrome/browser/autocomplete/history_contents_provider.h4
-rw-r--r--chrome/browser/autocomplete/history_contents_provider_unittest.cc33
-rw-r--r--chrome/browser/autocomplete/history_url_provider.cc12
-rw-r--r--chrome/browser/autocomplete/history_url_provider.h6
-rw-r--r--chrome/browser/autocomplete/history_url_provider_unittest.cc4
-rw-r--r--chrome/browser/autocomplete/keyword_provider.cc3
-rw-r--r--chrome/browser/autocomplete/keyword_provider.h3
-rw-r--r--chrome/browser/autocomplete/keyword_provider_unittest.cc4
-rw-r--r--chrome/browser/autocomplete/search_provider.cc21
-rw-r--r--chrome/browser/autocomplete/search_provider.h7
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