Chromium Code Reviews| Index: chrome/browser/instant/instant_controller.cc |
| diff --git a/chrome/browser/instant/instant_controller.cc b/chrome/browser/instant/instant_controller.cc |
| index 0c0f54706186ed867be074c5b94ac6579ce32d6f..293fd04beef5aec6148193b75babb129acb58d3f 100644 |
| --- a/chrome/browser/instant/instant_controller.cc |
| +++ b/chrome/browser/instant/instant_controller.cc |
| @@ -176,11 +176,12 @@ bool InstantController::Update(const AutocompleteMatch& match, |
| DCHECK(!omnibox_popup_is_open || user_input_in_progress); |
| // If the popup is closed, there should be no inline autocompletion. |
| - DCHECK(omnibox_popup_is_open || user_text == full_text) << user_text << "|" |
| - << full_text; |
| + DCHECK(omnibox_popup_is_open || user_text.empty() || user_text == full_text) |
| + << user_text << "|" << full_text; |
| // If there's inline autocompletion, the query has to be verbatim. |
| - DCHECK(user_text == full_text || verbatim) << user_text << "|" << full_text; |
| + DCHECK(user_text.empty() || user_text == full_text || verbatim) |
| + << user_text << "|" << full_text; |
| // If there's no text in the omnibox, the user can't have typed any. |
| DCHECK(!full_text.empty() || user_text.empty()) << user_text; |
| @@ -204,6 +205,21 @@ bool InstantController::Update(const AutocompleteMatch& match, |
| return false; |
| } |
| + // Ensure we have a loader that can process this match. First, try to use the |
| + // TemplateURL of the |match|. If that's invalid, in non-extended mode, stop. |
| + // In extended mode, try using the default search engine, but only when the |
| + // match is for a URL (i.e., not some other kind of non-Instant search). |
| + // A completely blank query shows up as a search, and we do want to allow |
| + // that, hence the "!user_text.empty()" clause. |
| + Profile* const profile = active_tab->profile(); |
| + const bool match_is_search = AutocompleteMatch::IsSearchType(match.type); |
| + if (!ResetLoader(match.GetTemplateURL(profile, false), active_tab) && |
|
Jered
2012/11/27 19:21:57
Why reset the loader here if client_ is set?
sreeram
2012/11/29 07:33:19
Done.
|
| + (!extended_enabled_ || (match_is_search && !user_text.empty()) || |
| + (!client_ && !CreateDefaultLoader()))) { |
| + Hide(true); |
| + return false; |
| + } |
| + |
| // Legend: OPIO == |omnibox_popup_is_open|, UIIP = |user_input_in_progress|. |
| // |
| // # OPIO UIIP full_text Notes |
| @@ -226,40 +242,47 @@ bool InstantController::Update(const AutocompleteMatch& match, |
| // |
| // In extended mode, #2 and #4 call Hide(). #1 doesn't Hide() as the preview |
| // may be showing custom NTP content, but doesn't Update() either. #3 and #7 |
| - // don't Hide(), but send a blank query to Update(). #8 calls Update(). |
| + // don't Hide(), and send a blank query to Update(). #8 calls Update(). |
| if (extended_enabled_) { |
| if (!omnibox_popup_is_open) { |
| - if (!full_text.empty()) { |
| - Hide(true); |
| - return false; |
| + if (!user_input_in_progress) { |
| + if (!full_text.empty()) { |
| + Hide(true); // #2 |
|
samarth
2012/11/27 18:09:43
Mostly for my understanding: Hide() will be a no-o
sreeram
2012/11/29 07:33:19
No, Hide() won't be a no-op. For one, it will actu
|
| + // If the user hit Escape when on a search results page, restore the |
| + // original results by resending the query. If the user was not on a |
| + // search results page, SearchModeChanged() would've caught it, and |
| + // |client_| will be NULL, so we won't accidentally send non-query |
| + // |full_text| to |client_|. Except if the user just switched tabs. |
| + // Hence the comparison of WebContents, to catch that case as well. |
| + if (client_ && client_->contents() == active_tab->web_contents()) |
| + client_->Update(full_text, true); |
| + } |
| + return false; // #1 |
| + } else { |
| + if (!full_text.empty()) { |
| + Hide(true); // #4 |
| + if (match_is_search) { |
| + // The user just switched to a tab with a partial query already in |
| + // the omnibox. This tab may or may not be a search results page |
| + // (SearchModeChanged() hasn't been called yet). So, assume that it |
| + // could be, and store |full_text| so that if the user then hits |
| + // Enter, we'll send the correct query in client_->Submit(). |
| + last_full_text_ = full_text; |
| + last_match_was_search_ = true; |
| + } |
| + return false; |
| + } |
| } |
| - if (!user_input_in_progress && full_text.empty()) |
| - return false; |
| } |
| } else if (!omnibox_popup_is_open || full_text.empty()) { |
| // Update() can be called if the user clicks the preview while composing |
| // text with an IME. If so, we should commit on mouse up, so don't Hide(). |
| - if (!GetPreviewContents() || !loader_->IsPointerDownFromActivate()) |
| + if (!loader_ || !loader_->IsPointerDownFromActivate()) |
| Hide(true); |
| return false; |
| } |
| - // Ensure we have a loader that can process this match. First, try to use the |
| - // TemplateURL of the |match|. If that's invalid, in non-extended mode, stop. |
| - // In extended mode, try using the default search engine, but only when the |
| - // match is for a URL (i.e., not some other kind of non-Instant search). |
| - // A completely blank query shows up as a search, and we do want to allow |
| - // that, hence the "!full_text.empty()" clause. |
| - Profile* const profile = active_tab->profile(); |
| - const bool match_is_search = AutocompleteMatch::IsSearchType(match.type); |
| - if (!ResetLoader(match.GetTemplateURL(profile, false), active_tab) && |
| - (!extended_enabled_ || (match_is_search && !full_text.empty()) || |
| - !CreateDefaultLoader())) { |
| - Hide(true); |
| - return false; |
| - } |
| - |
| // If the user continues typing the same query as the suggested text is |
| // showing, reuse the suggestion (but only for INSTANT_COMPLETE_NEVER). |
| bool reused_suggestion = false; |
| @@ -288,7 +311,7 @@ bool InstantController::Update(const AutocompleteMatch& match, |
| url_for_history_ = match.destination_url; |
| // Store the first interaction time for use with latency histograms. |
| - if (first_interaction_time_.is_null()) |
| + if (loader_ == CurrentClient() && first_interaction_time_.is_null()) |
|
Jered
2012/11/27 19:21:57
Please extract a method like IsCommitted() for loa
sreeram
2012/11/29 07:33:19
I've gone with the simpler "if (instant_tab_)" idi
|
| first_interaction_time_ = base::Time::Now(); |
| // Allow search suggestions. In extended mode, SearchModeChanged() will set |
| @@ -296,7 +319,10 @@ bool InstantController::Update(const AutocompleteMatch& match, |
| if (!extended_enabled_) |
| search_mode_.mode = chrome::search::Mode::MODE_SEARCH_SUGGESTIONS; |
| - loader_->Update(extended_enabled_ ? user_text : full_text, verbatim); |
| + CurrentClient()->Update(extended_enabled_ ? user_text : full_text, verbatim); |
| + |
| + if (loader_ == CurrentClient()) |
| + loader_->DidNavigate(history::HistoryAddPageArgs()); |
| content::NotificationService::current()->Notify( |
| chrome::NOTIFICATION_INSTANT_CONTROLLER_UPDATED, |
| @@ -338,9 +364,6 @@ void InstantController::HandleAutocompleteResults( |
| if (!extended_enabled_) |
| return; |
|
sky
2012/11/27 01:07:51
Shouldn't we early out if no client?
sreeram
2012/11/29 07:33:19
Done.
|
| - if (!GetPreviewContents()) |
| - return; |
| - |
| DVLOG(1) << "AutocompleteResults:"; |
| std::vector<InstantAutocompleteResult> results; |
| for (ACProviders::const_iterator provider = providers.begin(); |
| @@ -360,18 +383,20 @@ void InstantController::HandleAutocompleteResults( |
| } |
| } |
| - loader_->SendAutocompleteResults(results); |
| + if (InstantClient* client = CurrentClient()) |
|
samarth
2012/11/27 18:09:43
nit: does the Chrome style guide allow this? I hav
sreeram
2012/11/29 07:33:19
The style guide doesn't mention it. @sky hates it.
|
| + client->SendAutocompleteResults(results); |
| } |
| bool InstantController::OnUpOrDownKeyPressed(int count) { |
| if (!extended_enabled_) |
| return false; |
| - if (!GetPreviewContents()) |
| - return false; |
| + if (InstantClient* client = CurrentClient()) { |
| + client->UpOrDownKeyPressed(count); |
| + return true; |
| + } |
| - loader_->OnUpOrDownKeyPressed(count); |
| - return true; |
| + return false; |
| } |
| TabContents* InstantController::GetPreviewContents() const { |
| @@ -386,11 +411,24 @@ bool InstantController::CommitIfCurrent(InstantCommitType type) { |
| if (!extended_enabled_ && !instant_enabled_) |
| return false; |
| + if (client_ == CurrentClient() && last_match_was_search_ && |
|
Jered
2012/11/27 19:21:57
I am very confused. Why doesn't this cancel someti
sreeram
2012/11/29 07:33:19
Cancel() isn't applicable in the case of a committ
|
| + type == INSTANT_COMMIT_PRESSED_ENTER) { |
| + client_->Submit(last_full_text_); |
| + return true; |
| + } |
| + |
| if (!IsCurrent()) |
| return false; |
| DVLOG(1) << "CommitIfCurrent"; |
| - TabContents* preview = loader_->ReleasePreviewContents(type, last_full_text_); |
| + |
| + if (type == INSTANT_COMMIT_FOCUS_LOST) |
| + loader_->Cancel(last_full_text_); |
| + else |
| + loader_->Submit(last_full_text_); |
| + loader_->CleanupPreviewContents(); |
| + |
| + TabContents* preview = loader_->release_preview_contents(); |
| if (extended_enabled_) { |
| // Consider what's happening: |
| @@ -494,7 +532,7 @@ void InstantController::OmniboxLostFocus(gfx::NativeView view_gaining_focus) { |
| Hide(true); |
| #else |
| if (IsViewInContents(GetViewGainingFocus(view_gaining_focus), |
| - GetPreviewContents()->web_contents())) |
| + loader_->contents())) |
| CommitIfCurrent(INSTANT_COMMIT_FOCUS_LOST); |
| else |
| Hide(true); |
| @@ -508,7 +546,7 @@ void InstantController::OmniboxGotFocus() { |
| if (!extended_enabled_ && !instant_enabled_) |
| return; |
| - if (!GetPreviewContents()) |
| + if (!client_ && !loader_) |
| CreateDefaultLoader(); |
| } |
| @@ -531,8 +569,10 @@ void InstantController::SearchModeChanged( |
| Hide(true); |
| } |
| - if (GetPreviewContents()) |
| + if (loader_) |
| loader_->SearchModeChanged(new_mode); |
| + |
| + ResetClient(); |
| } |
| void InstantController::ActiveTabChanged() { |
| @@ -548,6 +588,9 @@ void InstantController::ActiveTabChanged() { |
| if (search_mode_.is_search_suggestions() && |
| model_.mode().is_search_suggestions()) |
| Hide(false); |
| + |
| + if (extended_enabled_) |
| + ResetClient(); |
| } |
| void InstantController::SetInstantEnabled(bool instant_enabled) { |
| @@ -560,7 +603,7 @@ void InstantController::ThemeChanged(const ThemeBackgroundInfo& theme_info) { |
| if (!extended_enabled_) |
| return; |
| - if (GetPreviewContents()) |
| + if (loader_) |
| loader_->SendThemeBackgroundInfo(theme_info); |
| } |
| @@ -568,15 +611,15 @@ void InstantController::ThemeAreaHeightChanged(int height) { |
| if (!extended_enabled_) |
| return; |
| - if (GetPreviewContents()) |
| + if (loader_) |
| loader_->SendThemeAreaHeight(height); |
| } |
| void InstantController::SetSuggestions( |
| - InstantLoader* loader, |
| + InstantClient* client, |
| const std::vector<InstantSuggestion>& suggestions) { |
| DVLOG(1) << "SetSuggestions"; |
| - if (loader_ != loader || !search_mode_.is_search_suggestions()) |
| + if (client != CurrentClient() || !search_mode_.is_search_suggestions()) |
| return; |
| InstantSuggestion suggestion; |
| @@ -659,8 +702,18 @@ void InstantController::ShowInstantPreview(InstantLoader* loader, |
| Show(reason, height, units); |
| } |
| -void InstantController::InstantSupportDetermined(InstantLoader* loader, |
| +void InstantController::InstantSupportDetermined(InstantClient* client, |
| bool supports_instant) { |
| + if (client_ == client) { |
| + if (!supports_instant) { |
| + // TODO(sreeram): This should be scheduled for later deletion, but we need |
| + // to disconnect the observer before doing so. |
| + client_.reset(); |
| + } |
| + return; |
| + } |
| + |
| + InstantLoader* loader = static_cast<InstantLoader*>(client); |
| if (supports_instant) { |
| blacklisted_urls_.erase(loader->instant_url()); |
| } else { |
| @@ -689,16 +742,34 @@ void InstantController::InstantLoaderContentsFocused(InstantLoader* loader) { |
| #endif |
| } |
| +void InstantController::ResetClient() { |
| + if (search_mode_.is_origin_search()) { |
| + content::WebContents* contents = |
| + browser_->GetActiveTabContents()->web_contents(); |
| + if (!client_ || contents != client_->contents()) { |
| + client_.reset(new InstantClient(this, contents)); |
| + client_->DetermineIfPageSupportsInstant(); |
| + } |
| + // We are now using |client_| instead of |loader_|, so Hide() the latter. We |
| + // want to call Hide(true) to clear old query results on the |loader_|, but |
| + // that would also clear |last_full_text_|, which is bad if the user then |
| + // immediately tries to commit the query on |client_|. |
| + Hide(!search_mode_.is_search_suggestions()); |
| + } else { |
| + client_.reset(); |
| + } |
| +} |
| + |
| bool InstantController::ResetLoader(const TemplateURL* template_url, |
| const TabContents* active_tab) { |
| std::string instant_url; |
| if (!GetInstantURL(template_url, &instant_url)) |
| return false; |
| - if (GetPreviewContents() && loader_->instant_url() != instant_url) |
| + if (loader_ && loader_->instant_url() != instant_url) |
| DeleteLoader(); |
| - if (!GetPreviewContents()) { |
| + if (!loader_) { |
| loader_.reset(new InstantLoader(this, instant_url, active_tab)); |
| loader_->Init(); |
| @@ -735,7 +806,7 @@ void InstantController::OnStaleLoader() { |
| // If the preview is showing or the omnibox has focus, don't delete the |
| // loader. It will get refreshed the next time the preview is hidden or the |
| // omnibox loses focus. |
| - if (!stale_loader_timer_.IsRunning() && !is_omnibox_focused_ && |
| + if (!stale_loader_timer_.IsRunning() && !is_omnibox_focused_ && !client_ && |
| model_.mode().is_default()) { |
| DeleteLoader(); |
| CreateDefaultLoader(); |
| @@ -796,6 +867,9 @@ void InstantController::Hide(bool clear_query) { |
| void InstantController::Show(InstantShownReason reason, |
| int height, |
| InstantSizeUnits units) { |
| + if (client_ == CurrentClient()) |
| + return; |
| + |
| DVLOG(1) << "Show: reason=" << reason << " height=" << height << " units=" |
| << units; |
| @@ -819,8 +893,8 @@ void InstantController::Show(InstantShownReason reason, |
| } |
| void InstantController::SendBoundsToPage() { |
| - if (last_omnibox_bounds_ == omnibox_bounds_ || |
| - !GetPreviewContents() || loader_->IsPointerDownFromActivate()) |
| + if (last_omnibox_bounds_ == omnibox_bounds_ || !loader_ || |
| + loader_->IsPointerDownFromActivate()) |
| return; |
| last_omnibox_bounds_ = omnibox_bounds_; |
| @@ -896,3 +970,7 @@ bool InstantController::GetInstantURL(const TemplateURL* template_url, |
| return true; |
| } |
| + |
| +InstantClient* InstantController::CurrentClient() const { |
| + return client_ ? client_.get() : loader_.get(); |
| +} |