diff options
author | sreeram@chromium.org <sreeram@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-12-04 19:14:59 +0000 |
---|---|---|
committer | sreeram@chromium.org <sreeram@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-12-04 19:14:59 +0000 |
commit | cd533bfe78bbc2aaed9cbb899797978e166cd306 (patch) | |
tree | 817e4c646aa9492b9431680d8b51ff749ea60231 /chrome | |
parent | d758e637ec2746870ca221d501d4726242f06c3e (diff) | |
download | chromium_src-cd533bfe78bbc2aaed9cbb899797978e166cd306.zip chromium_src-cd533bfe78bbc2aaed9cbb899797978e166cd306.tar.gz chromium_src-cd533bfe78bbc2aaed9cbb899797978e166cd306.tar.bz2 |
Persist the Instant API to committed search result pages.
Whenever the active tab is an Instant search results page,
|instant_tab_| is used to talk the Instant API with it.
Also:
+ Replace uses of TabContents with WebContents as much as possible (in
service of @avi's goal, http://crbug.com/107201).
+ Aggressively create the InstantLoader in many situations; update
browser tests accordingly.
+ Don't send an initial resize on page load. This was only relevant for
the erstwhile hidden Instant modes.
+ Delay delete the loader only when strictly necessary, such as when an
InstantLoader method is on the call stack. At other times, prefer the
much simpler loader_.reset().
+ Don't bother resetting state. Resetting state has no practical
benefit, since we already only use state variables when they are
valid. Instead, this avoids tricky situations where we should NOT
reset state just because the |loader_| is deleted (since the
|instant_tab_| may still be in use).
+ Given the above two, remove DeleteLoader() entirely.
+ Separate out the magic in Hide() into three pieces: Hide(),
HideInternal() and a couple of places where we want to preserve
|last_full_text_|. I think this makes things slightly clearer.
BUG=158942
R=jered@chromium.org,samarth@chromium.org,sky@chromium.org
TEST=Commit a query. Change mode to News. Type another query. You should
see results in News mode.
Review URL: https://chromiumcodereview.appspot.com/11421079
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@171018 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
36 files changed, 1252 insertions, 910 deletions
diff --git a/chrome/browser/automation/testing_automation_provider.cc b/chrome/browser/automation/testing_automation_provider.cc index 30e7d1e..5571d8c 100644 --- a/chrome/browser/automation/testing_automation_provider.cc +++ b/chrome/browser/automation/testing_automation_provider.cc @@ -3193,9 +3193,8 @@ void TestingAutomationProvider::GetInstantInfo(Browser* browser, info->SetBoolean("enabled", true); info->SetBoolean("active", (instant->GetPreviewContents() != NULL)); info->SetBoolean("current", instant->IsCurrent()); - if (instant->GetPreviewContents() && - instant->GetPreviewContents()->web_contents()) { - WebContents* contents = instant->GetPreviewContents()->web_contents(); + if (instant->GetPreviewContents()) { + WebContents* contents = instant->GetPreviewContents(); info->SetBoolean("loading", contents->IsLoading()); info->SetString("location", contents->GetURL().spec()); info->SetString("title", contents->GetTitle()); diff --git a/chrome/browser/instant/instant_browsertest.cc b/chrome/browser/instant/instant_browsertest.cc index e85d755..ce147fe 100644 --- a/chrome/browser/instant/instant_browsertest.cc +++ b/chrome/browser/instant/instant_browsertest.cc @@ -17,7 +17,6 @@ #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/omnibox/location_bar.h" #include "chrome/browser/ui/omnibox/omnibox_view.h" -#include "chrome/browser/ui/tab_contents/tab_contents.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/common/chrome_notification_types.h" #include "chrome/common/pref_names.h" @@ -145,8 +144,8 @@ class InstantTest : public InProcessBrowserTest { rvh, std::wstring(), WrapScript(script), result); } - bool UpdateSearchState(TabContents* tab) WARN_UNUSED_RESULT { - content::RenderViewHost* rvh = tab->web_contents()->GetRenderViewHost(); + bool UpdateSearchState(content::WebContents* contents) WARN_UNUSED_RESULT { + content::RenderViewHost* rvh = contents->GetRenderViewHost(); return GetIntFromJS(rvh, "onvisibilitycalls", &onvisibilitycalls_) && GetIntFromJS(rvh, "onchangecalls", &onchangecalls_) && GetIntFromJS(rvh, "onsubmitcalls", &onsubmitcalls_) && @@ -159,15 +158,16 @@ class InstantTest : public InProcessBrowserTest { bool ExecuteScript(const std::string& script) WARN_UNUSED_RESULT { return content::ExecuteJavaScript( - instant()->GetPreviewContents()->web_contents()->GetRenderViewHost(), - std::wstring(), UTF8ToWide(script)); + instant()->GetPreviewContents()->GetRenderViewHost(), std::wstring(), + UTF8ToWide(script)); } - bool CheckVisibilityIs(TabContents* tab, bool expected) WARN_UNUSED_RESULT { + bool CheckVisibilityIs(content::WebContents* contents, + bool expected) WARN_UNUSED_RESULT { bool actual = !expected; // Purposely start with a mis-match. // We can only use ASSERT_*() in a method that returns void, hence this // convoluted check. - return GetBoolFromJS(tab->web_contents()->GetRenderViewHost(), + return GetBoolFromJS(contents->GetRenderViewHost(), "!document.webkitHidden", &actual) && actual == expected; } @@ -187,11 +187,7 @@ class InstantTest : public InProcessBrowserTest { // Test that Instant is preloaded when the omnibox is focused. IN_PROC_BROWSER_TEST_F(InstantTest, OmniboxFocusLoadsInstant) { - // The omnibox gets focus before the test begins. At this time, there's no - // InstantController (which is only created in SetupInstant() below), so no - // preloading has happened yet. ASSERT_NO_FATAL_FAILURE(SetupInstant()); - EXPECT_FALSE(instant()->GetPreviewContents()); // Explicitly unfocus the omnibox. EXPECT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); @@ -200,21 +196,25 @@ IN_PROC_BROWSER_TEST_F(InstantTest, OmniboxFocusLoadsInstant) { EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_TAB_CONTAINER)); EXPECT_FALSE(omnibox()->model()->has_focus()); + // Delete any existing preview. + instant()->loader_.reset(); + EXPECT_FALSE(instant()->GetPreviewContents()); + // Refocus the omnibox. The InstantController should've preloaded Instant. FocusOmniboxAndWaitForInstantSupport(); EXPECT_FALSE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_TAB_CONTAINER)); EXPECT_TRUE(omnibox()->model()->has_focus()); - TabContents* preview_tab = instant()->GetPreviewContents(); + content::WebContents* preview_tab = instant()->GetPreviewContents(); EXPECT_TRUE(preview_tab); // Check that the page supports Instant, but it isn't showing. - EXPECT_TRUE(instant()->loader()->supports_instant()); + EXPECT_TRUE(instant()->loader_->supports_instant()); EXPECT_FALSE(instant()->IsCurrent()); EXPECT_TRUE(instant()->model()->mode().is_default()); - // Adding a new tab shouldn't delete or recreate the TabContents; otherwise, + // Adding a new tab shouldn't delete or recreate the preview; otherwise, // what's the point of preloading? AddBlankTabAndShow(browser()); EXPECT_EQ(preview_tab, instant()->GetPreviewContents()); @@ -283,7 +283,7 @@ IN_PROC_BROWSER_TEST_F(InstantTest, OnSubmitEvent) { SetOmniboxTextAndWaitForInstantToShow("search"); // Stash a reference to the preview, so we can refer to it after commit. - TabContents* preview_tab = instant()->GetPreviewContents(); + content::WebContents* preview_tab = instant()->GetPreviewContents(); EXPECT_TRUE(preview_tab); // The state of the searchbox before the commit. @@ -294,10 +294,10 @@ IN_PROC_BROWSER_TEST_F(InstantTest, OnSubmitEvent) { EXPECT_EQ(1, onvisibilitycalls_); // Before the commit, the active tab is the NTP (i.e., not Instant). - TabContents* active_tab = - browser()->tab_strip_model()->GetActiveTabContents(); + content::WebContents* active_tab = + browser()->tab_strip_model()->GetActiveWebContents(); EXPECT_NE(preview_tab, active_tab); - EXPECT_EQ(1, active_tab->web_contents()->GetController().GetEntryCount()); + EXPECT_EQ(1, active_tab->GetController().GetEntryCount()); EXPECT_EQ(std::string(chrome::kAboutBlankURL), omnibox()->model()->PermanentURL().spec()); @@ -313,18 +313,18 @@ IN_PROC_BROWSER_TEST_F(InstantTest, OnSubmitEvent) { EXPECT_NE(instant()->GetPreviewContents(), preview_tab); // Check that the current active tab is indeed what was once the preview. - EXPECT_EQ(preview_tab, browser()->tab_strip_model()->GetActiveTabContents()); + EXPECT_EQ(preview_tab, browser()->tab_strip_model()->GetActiveWebContents()); // We should have two navigation entries, one for the NTP, and one for the // Instant search that was committed. - EXPECT_EQ(2, preview_tab->web_contents()->GetController().GetEntryCount()); + EXPECT_EQ(2, preview_tab->GetController().GetEntryCount()); // Check that the omnibox contains the Instant URL we loaded. EXPECT_EQ(instant_url_, omnibox()->model()->PermanentURL()); // Check that the searchbox API values have been reset. std::string value; - EXPECT_TRUE(GetStringFromJS(preview_tab->web_contents()->GetRenderViewHost(), + EXPECT_TRUE(GetStringFromJS(preview_tab->GetRenderViewHost(), "chrome.searchBox.value", &value)); EXPECT_EQ("", value); @@ -344,7 +344,7 @@ IN_PROC_BROWSER_TEST_F(InstantTest, OnCancelEvent) { SetOmniboxTextAndWaitForInstantToShow("search"); // Stash a reference to the preview, so we can refer to it after commit. - TabContents* preview_tab = instant()->GetPreviewContents(); + content::WebContents* preview_tab = instant()->GetPreviewContents(); EXPECT_TRUE(preview_tab); // The state of the searchbox before the commit. @@ -355,10 +355,10 @@ IN_PROC_BROWSER_TEST_F(InstantTest, OnCancelEvent) { EXPECT_EQ(1, onvisibilitycalls_); // Before the commit, the active tab is the NTP (i.e., not Instant). - TabContents* active_tab = - browser()->tab_strip_model()->GetActiveTabContents(); + content::WebContents* active_tab = + browser()->tab_strip_model()->GetActiveWebContents(); EXPECT_NE(preview_tab, active_tab); - EXPECT_EQ(1, active_tab->web_contents()->GetController().GetEntryCount()); + EXPECT_EQ(1, active_tab->GetController().GetEntryCount()); EXPECT_EQ(std::string(chrome::kAboutBlankURL), omnibox()->model()->PermanentURL().spec()); @@ -374,18 +374,18 @@ IN_PROC_BROWSER_TEST_F(InstantTest, OnCancelEvent) { EXPECT_NE(instant()->GetPreviewContents(), preview_tab); // Check that the current active tab is indeed what was once the preview. - EXPECT_EQ(preview_tab, browser()->tab_strip_model()->GetActiveTabContents()); + EXPECT_EQ(preview_tab, browser()->tab_strip_model()->GetActiveWebContents()); // We should have two navigation entries, one for the NTP, and one for the // Instant search that was committed. - EXPECT_EQ(2, preview_tab->web_contents()->GetController().GetEntryCount()); + EXPECT_EQ(2, preview_tab->GetController().GetEntryCount()); // Check that the omnibox contains the Instant URL we loaded. EXPECT_EQ(instant_url_, omnibox()->model()->PermanentURL()); // Check that the searchbox API values have been reset. std::string value; - EXPECT_TRUE(GetStringFromJS(preview_tab->web_contents()->GetRenderViewHost(), + EXPECT_TRUE(GetStringFromJS(preview_tab->GetRenderViewHost(), "chrome.searchBox.value", &value)); EXPECT_EQ("", value); @@ -401,12 +401,10 @@ IN_PROC_BROWSER_TEST_F(InstantTest, OnCancelEvent) { IN_PROC_BROWSER_TEST_F(InstantTest, OnResizeEvent) { ASSERT_NO_FATAL_FAILURE(SetupInstant()); - // This makes Instant load the preview, along with an initial onresize() (see - // SearchBoxExtension::PageSupportsInstant() for why). FocusOmniboxAndWaitForInstantSupport(); EXPECT_TRUE(UpdateSearchState(instant()->GetPreviewContents())); - EXPECT_EQ(1, onresizecalls_); + EXPECT_EQ(0, onresizecalls_); EXPECT_EQ(0, height_); // Type a query into the omnibox. This should cause an onresize() event, with @@ -414,7 +412,7 @@ IN_PROC_BROWSER_TEST_F(InstantTest, OnResizeEvent) { SetOmniboxTextAndWaitForInstantToShow("search"); EXPECT_TRUE(UpdateSearchState(instant()->GetPreviewContents())); - EXPECT_EQ(2, onresizecalls_); + EXPECT_EQ(1, onresizecalls_); EXPECT_LT(0, height_); } @@ -534,7 +532,6 @@ IN_PROC_BROWSER_TEST_F(InstantTest, RejectsURLs) { // Make sure that the URLs were never sent to the preview page. EXPECT_TRUE(UpdateSearchState(instant()->GetPreviewContents())); - EXPECT_EQ(0, onchangecalls_); EXPECT_EQ("", value_); } @@ -633,7 +630,7 @@ IN_PROC_BROWSER_TEST_F(InstantTest, DoesNotCommitURLsOne) { EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_TAB_CONTAINER)); FocusOmnibox(); - TabContents* preview_tab = instant()->GetPreviewContents(); + content::WebContents* preview_tab = instant()->GetPreviewContents(); EXPECT_TRUE(preview_tab); // The omnibox text hasn't changed, so Instant still shouldn't be showing. @@ -643,8 +640,8 @@ IN_PROC_BROWSER_TEST_F(InstantTest, DoesNotCommitURLsOne) { // Commit the URL. The omnibox should reflect the URL minus the scheme. browser()->window()->GetLocationBar()->AcceptInput(); - TabContents* active_tab = - browser()->tab_strip_model()->GetActiveTabContents(); + content::WebContents* active_tab = + browser()->tab_strip_model()->GetActiveWebContents(); EXPECT_NE(preview_tab, active_tab); EXPECT_EQ(ASCIIToUTF16("deadly/nadder"), omnibox()->GetText()); @@ -662,7 +659,7 @@ IN_PROC_BROWSER_TEST_F(InstantTest, DoesNotCommitURLsTwo) { // Type a query. This causes the preview to be shown. SetOmniboxTextAndWaitForInstantToShow("query"); - TabContents* preview_tab = instant()->GetPreviewContents(); + content::WebContents* preview_tab = instant()->GetPreviewContents(); EXPECT_TRUE(preview_tab); // Type a URL. This causes the preview to be hidden. @@ -676,8 +673,8 @@ IN_PROC_BROWSER_TEST_F(InstantTest, DoesNotCommitURLsTwo) { // Commit the URL. As before, check that Instant wasn't committed. browser()->window()->GetLocationBar()->AcceptInput(); - TabContents* active_tab = - browser()->tab_strip_model()->GetActiveTabContents(); + content::WebContents* active_tab = + browser()->tab_strip_model()->GetActiveWebContents(); EXPECT_NE(preview_tab, active_tab); EXPECT_EQ(ASCIIToUTF16("hideous/zippleback"), omnibox()->GetText()); @@ -693,9 +690,11 @@ IN_PROC_BROWSER_TEST_F(InstantTest, NonInstantSearchProvider) { ASSERT_NO_FATAL_FAILURE(SetupInstant()); // Focus the omnibox. When the support determination response comes back, - // Instant will destroy the non-Instant page. + // Instant will destroy the non-Instant page, and attempt to recreate it. + // We can know this happened by looking at the blacklist. + EXPECT_EQ(0, instant()->blacklisted_urls_[instant_url_.spec()]); FocusOmniboxAndWaitForInstantSupport(); - EXPECT_FALSE(instant()->GetPreviewContents()); + EXPECT_EQ(1, instant()->blacklisted_urls_[instant_url_.spec()]); } // Test that the renderer doesn't crash if JavaScript is blocked. @@ -714,9 +713,9 @@ IN_PROC_BROWSER_TEST_F(InstantTest, PageVisibility) { ASSERT_NO_FATAL_FAILURE(SetupInstant()); FocusOmniboxAndWaitForInstantSupport(); - TabContents* active_tab = - browser()->tab_strip_model()->GetActiveTabContents(); - TabContents* preview_tab = instant()->GetPreviewContents(); + content::WebContents* active_tab = + browser()->tab_strip_model()->GetActiveWebContents(); + content::WebContents* preview_tab = instant()->GetPreviewContents(); // Inititally, the active tab is showing; the preview is not. EXPECT_TRUE(CheckVisibilityIs(active_tab, true)); @@ -739,7 +738,7 @@ IN_PROC_BROWSER_TEST_F(InstantTest, PageVisibility) { // Commit the preview. browser()->window()->GetLocationBar()->AcceptInput(); - EXPECT_EQ(preview_tab, browser()->tab_strip_model()->GetActiveTabContents()); + EXPECT_EQ(preview_tab, browser()->tab_strip_model()->GetActiveWebContents()); EXPECT_TRUE(CheckVisibilityIs(preview_tab, true)); } @@ -776,10 +775,10 @@ IN_PROC_BROWSER_TEST_F(InstantTest, TaskManagerPrefix) { void HistoryQueryDone(base::RunLoop* run_loop, bool* result, - HistoryService::Handle /* handle */, + HistoryService::Handle /* handle */, bool success, - const history::URLRow* /* urlrow */, - history::VisitVector* /* visitvector */) { + const history::URLRow* /* urlrow */, + history::VisitVector* /* visitvector */) { *result = success; run_loop->Quit(); } @@ -812,7 +811,6 @@ IN_PROC_BROWSER_TEST_F(InstantTest, History) { // Perform a search. SetOmniboxTextAndWaitForInstantToShow("search"); - EXPECT_EQ(instant_url_.spec(), instant()->loader()->instant_url()); // Commit the search. browser()->window()->GetLocationBar()->AcceptInput(); @@ -887,23 +885,23 @@ IN_PROC_BROWSER_TEST_F(InstantTest, InstantLoaderRefresh) { SetOmniboxTextAndWaitForInstantToShow("query"); instant()->stale_loader_timer_.Stop(); instant()->OnStaleLoader(); - EXPECT_TRUE(instant()->loader()->supports_instant()); - instant()->Hide(true); - EXPECT_TRUE(instant()->loader()->supports_instant()); + EXPECT_TRUE(instant()->loader_->supports_instant()); + instant()->HideLoader(); + EXPECT_TRUE(instant()->loader_->supports_instant()); instant()->OmniboxLostFocus(NULL); - EXPECT_FALSE(instant()->loader()->supports_instant()); + EXPECT_FALSE(instant()->loader_->supports_instant()); // Try with a different ordering. SetOmniboxTextAndWaitForInstantToShow("query"); instant()->stale_loader_timer_.Stop(); instant()->OnStaleLoader(); - EXPECT_TRUE(instant()->loader()->supports_instant()); + EXPECT_TRUE(instant()->loader_->supports_instant()); instant()->OmniboxLostFocus(NULL); - // TODO(sreeram): Currently, OmniboxLostFocus() calls Hide(). Eventually, - // when it stops hiding the preview, uncomment these two lines below: - // EXPECT_TRUE(instant()->loader()->supports_instant()); - // instant()->Hide(true); - EXPECT_FALSE(instant()->loader()->supports_instant()); + // TODO(sreeram): Currently, OmniboxLostFocus() calls HideLoader(). When it + // stops hiding the preview eventually, uncomment these two lines: + // EXPECT_TRUE(instant()->loader_->supports_instant()); + // instant()->HideLoader(); + EXPECT_FALSE(instant()->loader_->supports_instant()); } // Test that suggestions are case insensitive. http://crbug.com/150728 @@ -970,18 +968,18 @@ IN_PROC_BROWSER_TEST_F(InstantTest, CommitInNewTab) { // Use the Instant page as the active tab, so we can exploit its visibility // handler to check visibility transitions. ui_test_utils::NavigateToURL(browser(), instant_url_); - TabContents* active_tab = - browser()->tab_strip_model()->GetActiveTabContents(); + content::WebContents* active_tab = + browser()->tab_strip_model()->GetActiveWebContents(); int active_tab_onvisibilitycalls = -1; - EXPECT_TRUE(GetIntFromJS(active_tab->web_contents()->GetRenderViewHost(), - "onvisibilitycalls", &active_tab_onvisibilitycalls)); + EXPECT_TRUE(GetIntFromJS(active_tab->GetRenderViewHost(), "onvisibilitycalls", + &active_tab_onvisibilitycalls)); EXPECT_EQ(0, active_tab_onvisibilitycalls); SetOmniboxTextAndWaitForInstantToShow("search"); // Stash a reference to the preview, so we can refer to it after commit. - TabContents* preview_tab = instant()->GetPreviewContents(); + content::WebContents* preview_tab = instant()->GetPreviewContents(); EXPECT_TRUE(preview_tab); // The state of the searchbox before the commit. @@ -993,11 +991,11 @@ IN_PROC_BROWSER_TEST_F(InstantTest, CommitInNewTab) { // The state of the active tab before the commit. EXPECT_NE(preview_tab, active_tab); - EXPECT_EQ(2, active_tab->web_contents()->GetController().GetEntryCount()); + EXPECT_EQ(2, active_tab->GetController().GetEntryCount()); EXPECT_EQ(instant_url_, omnibox()->model()->PermanentURL()); active_tab_onvisibilitycalls = -1; - EXPECT_TRUE(GetIntFromJS(active_tab->web_contents()->GetRenderViewHost(), - "onvisibilitycalls", &active_tab_onvisibilitycalls)); + EXPECT_TRUE(GetIntFromJS(active_tab->GetRenderViewHost(), "onvisibilitycalls", + &active_tab_onvisibilitycalls)); EXPECT_EQ(0, active_tab_onvisibilitycalls); // Commit the search by pressing Alt-Enter. @@ -1015,15 +1013,15 @@ IN_PROC_BROWSER_TEST_F(InstantTest, CommitInNewTab) { // once the preview. The preview tab should have just one navigation entry, // for the Instant search that was committed. EXPECT_EQ(2, browser()->tab_strip_model()->count()); - EXPECT_EQ(preview_tab, browser()->tab_strip_model()->GetActiveTabContents()); - EXPECT_EQ(1, preview_tab->web_contents()->GetController().GetEntryCount()); + EXPECT_EQ(preview_tab, browser()->tab_strip_model()->GetActiveWebContents()); + EXPECT_EQ(1, preview_tab->GetController().GetEntryCount()); // Check that the omnibox contains the Instant URL we loaded. EXPECT_EQ(instant_url_, omnibox()->model()->PermanentURL()); // Check that the searchbox API values have been reset. std::string value; - EXPECT_TRUE(GetStringFromJS(preview_tab->web_contents()->GetRenderViewHost(), + EXPECT_TRUE(GetStringFromJS(preview_tab->GetRenderViewHost(), "chrome.searchBox.value", &value)); EXPECT_EQ("", value); @@ -1036,8 +1034,8 @@ IN_PROC_BROWSER_TEST_F(InstantTest, CommitInNewTab) { // The ex-active tab should've gotten a visibility change marking it hidden. EXPECT_NE(active_tab, preview_tab); - EXPECT_TRUE(GetIntFromJS(active_tab->web_contents()->GetRenderViewHost(), - "onvisibilitycalls", &active_tab_onvisibilitycalls)); + EXPECT_TRUE(GetIntFromJS(active_tab->GetRenderViewHost(), "onvisibilitycalls", + &active_tab_onvisibilitycalls)); EXPECT_EQ(1, active_tab_onvisibilitycalls); } diff --git a/chrome/browser/instant/instant_client.cc b/chrome/browser/instant/instant_client.cc new file mode 100644 index 0000000..5a4efc5 --- /dev/null +++ b/chrome/browser/instant/instant_client.cc @@ -0,0 +1,114 @@ +// Copyright 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/instant/instant_client.h" + +#include "chrome/common/render_messages.h" +#include "content/public/browser/web_contents.h" + +InstantClient::Delegate::~Delegate() { +} + +InstantClient::InstantClient(Delegate* delegate) : delegate_(delegate) { +} + +InstantClient::~InstantClient() { +} + +void InstantClient::SetContents(content::WebContents* contents) { + Observe(contents); +} + +void InstantClient::Update(const string16& text, + size_t selection_start, + size_t selection_end, + bool verbatim) { + Send(new ChromeViewMsg_SearchBoxChange(routing_id(), text, verbatim, + selection_start, selection_end)); +} + +void InstantClient::Submit(const string16& text) { + Send(new ChromeViewMsg_SearchBoxSubmit(routing_id(), text)); +} + +void InstantClient::Cancel(const string16& text) { + Send(new ChromeViewMsg_SearchBoxCancel(routing_id(), text)); +} + +void InstantClient::SetOmniboxBounds(const gfx::Rect& bounds) { + Send(new ChromeViewMsg_SearchBoxResize(routing_id(), bounds)); +} + +void InstantClient::DetermineIfPageSupportsInstant() { + Send(new ChromeViewMsg_DetermineIfPageSupportsInstant(routing_id())); +} + +void InstantClient::SendAutocompleteResults( + const std::vector<InstantAutocompleteResult>& results) { + Send(new ChromeViewMsg_SearchBoxAutocompleteResults(routing_id(), results)); +} + +void InstantClient::UpOrDownKeyPressed(int count) { + Send(new ChromeViewMsg_SearchBoxUpOrDownKeyPressed(routing_id(), count)); +} + +void InstantClient::SearchModeChanged(const chrome::search::Mode& mode) { + Send(new ChromeViewMsg_SearchBoxModeChanged(routing_id(), mode)); +} + +void InstantClient::SendThemeBackgroundInfo( + const ThemeBackgroundInfo& theme_info) { + Send(new ChromeViewMsg_SearchBoxThemeChanged(routing_id(), theme_info)); +} + +void InstantClient::SendThemeAreaHeight(int height) { + Send(new ChromeViewMsg_SearchBoxThemeAreaHeightChanged(routing_id(), height)); +} + +void InstantClient::SetDisplayInstantResults(bool display_instant_results) { + Send(new ChromeViewMsg_SearchBoxSetDisplayInstantResults(routing_id(), + display_instant_results)); +} + +void InstantClient::DidFinishLoad( + int64 /* frame_id */, + const GURL& /* validated_url */, + bool is_main_frame, + content::RenderViewHost* /* render_view_host */) { + if (is_main_frame) + DetermineIfPageSupportsInstant(); +} + +bool InstantClient::OnMessageReceived(const IPC::Message& message) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(InstantClient, message) + IPC_MESSAGE_HANDLER(ChromeViewHostMsg_SetSuggestions, SetSuggestions) + IPC_MESSAGE_HANDLER(ChromeViewHostMsg_InstantSupportDetermined, + InstantSupportDetermined) + IPC_MESSAGE_HANDLER(ChromeViewHostMsg_ShowInstantPreview, + ShowInstantPreview) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +void InstantClient::SetSuggestions( + int page_id, + const std::vector<InstantSuggestion>& suggestions) { + if (web_contents()->IsActiveEntry(page_id)) + delegate_->SetSuggestions(suggestions); +} + +void InstantClient::InstantSupportDetermined(int page_id, bool result) { + if (web_contents()->IsActiveEntry(page_id)) + delegate_->InstantSupportDetermined(result); +} + +void InstantClient::ShowInstantPreview(int page_id, + InstantShownReason reason, + int height, + InstantSizeUnits units) { + if (web_contents()->IsActiveEntry(page_id)) + delegate_->ShowInstantPreview(reason, height, units); +} diff --git a/chrome/browser/instant/instant_client.h b/chrome/browser/instant/instant_client.h new file mode 100644 index 0000000..1c213ad --- /dev/null +++ b/chrome/browser/instant/instant_client.h @@ -0,0 +1,132 @@ +// Copyright 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_INSTANT_INSTANT_CLIENT_H_ +#define CHROME_BROWSER_INSTANT_INSTANT_CLIENT_H_ + +#include <vector> + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "base/string16.h" +#include "chrome/common/instant_types.h" +#include "content/public/browser/web_contents_observer.h" + +namespace chrome { +namespace search { +struct Mode; +} +} + +namespace content { +class WebContents; +} + +namespace gfx { +class Rect; +} + +// InstantClient is used to exchange messages between its delegate and a page +// that supports the Instant API (http://dev.chromium.org/searchbox). +class InstantClient : public content::WebContentsObserver { + public: + // When InstantClient receives messages from the page, it calls the following + // methods on its delegate. + class Delegate { + public: + // Called when the page has suggestions. Usually in response to Change(), + // SendAutocompleteResults() or UpOrDownKeyPressed(). + virtual void SetSuggestions( + const std::vector<InstantSuggestion>& suggestions) = 0; + + // Called upon determination of Instant API support. Usually in response to + // SetContents() or when the page first finishes loading. + virtual void InstantSupportDetermined(bool supports_instant) = 0; + + // Called when the page wants to be shown. Usually in response to Change(), + // SendAutocompleteResults() or SearchModeChanged(). + virtual void ShowInstantPreview(InstantShownReason reason, + int height, + InstantSizeUnits units) = 0; + + protected: + virtual ~Delegate(); + }; + + // Doesn't take ownership of |delegate|. + explicit InstantClient(Delegate* delegate); + virtual ~InstantClient(); + + // Sets |contents| as the page to communicate with. |contents| can be NULL, + // which effectively stops all communication. + void SetContents(content::WebContents* contents); + + // Tells the page that the user typed |text| into the omnibox. If |verbatim| + // is false, the page predicts the query the user means to type and fetches + // results for the prediction. If |verbatim| is true, |text| is taken as the + // exact query (no prediction is made). + void Update(const string16& text, + size_t selection_start, + size_t selection_end, + bool verbatim); + + // Tells the page that the user pressed Enter in the omnibox. + void Submit(const string16& text); + + // Tells the page that the user clicked on it. Nothing is being cancelled; the + // poor choice of name merely reflects the IPC of the same (poor) name. + void Cancel(const string16& text); + + // Tells the page the bounds of the omnibox dropdown (in screen coordinates). + // This is used by the page to offset the results to avoid them being covered + // by the omnibox dropdown. + void SetOmniboxBounds(const gfx::Rect& bounds); + + // Tells the renderer to determine if the page supports the Instant API, which + // results in a call to InstantSupportDetermined() when the reply is received. + void DetermineIfPageSupportsInstant(); + + // Tells the page about the available autocomplete results. + void SendAutocompleteResults( + const std::vector<InstantAutocompleteResult>& results); + + // Tells the page that the user pressed Up or Down in the omnibox. |count| is + // a repeat count, negative for moving up, positive for moving down. + void UpOrDownKeyPressed(int count); + + // Tells the page that the active tab's search mode has changed. + void SearchModeChanged(const chrome::search::Mode& mode); + + // Tells the page about the current theme background. + void SendThemeBackgroundInfo(const ThemeBackgroundInfo& theme_info); + + // Tells the page about the current theme area height. + void SendThemeAreaHeight(int height); + + // Tells the page whether it is allowed to display Instant results. + void SetDisplayInstantResults(bool display_instant_results); + + private: + // Overridden from content::WebContentsObserver: + virtual void DidFinishLoad( + int64 frame_id, + const GURL& validated_url, + bool is_main_frame, + content::RenderViewHost* render_view_host) OVERRIDE; + virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; + + void SetSuggestions(int page_id, + const std::vector<InstantSuggestion>& suggestions); + void InstantSupportDetermined(int page_id, bool result); + void ShowInstantPreview(int page_id, + InstantShownReason reason, + int height, + InstantSizeUnits units); + + Delegate* const delegate_; + + DISALLOW_COPY_AND_ASSIGN(InstantClient); +}; + +#endif // CHROME_BROWSER_INSTANT_INSTANT_CLIENT_H_ diff --git a/chrome/browser/instant/instant_commit_type.h b/chrome/browser/instant/instant_commit_type.h index 2718639..b025542 100644 --- a/chrome/browser/instant/instant_commit_type.h +++ b/chrome/browser/instant/instant_commit_type.h @@ -1,4 +1,4 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. diff --git a/chrome/browser/instant/instant_controller.cc b/chrome/browser/instant/instant_controller.cc index 95d7c43..f6c7725 100644 --- a/chrome/browser/instant/instant_controller.cc +++ b/chrome/browser/instant/instant_controller.cc @@ -14,12 +14,12 @@ #include "chrome/browser/history/history_service_factory.h" #include "chrome/browser/history/history_tab_helper.h" #include "chrome/browser/instant/instant_loader.h" +#include "chrome/browser/instant/instant_tab.h" #include "chrome/browser/platform_util.h" #include "chrome/browser/search_engines/template_url_service.h" #include "chrome/browser/search_engines/template_url_service_factory.h" #include "chrome/browser/ui/browser_instant_controller.h" #include "chrome/browser/ui/search/search_tab_helper.h" -#include "chrome/browser/ui/tab_contents/tab_contents.h" #include "chrome/common/chrome_notification_types.h" #include "chrome/common/chrome_switches.h" #include "content/public/browser/navigation_entry.h" @@ -48,16 +48,16 @@ const int kMaxInstantSupportFailures = 10; const int kStaleLoaderTimeoutMS = 3 * 3600 * 1000; void AddSessionStorageHistogram(bool extended_enabled, - const TabContents* tab1, - const TabContents* tab2) { + const content::WebContents* tab1, + const content::WebContents* tab2) { base::Histogram* histogram = base::BooleanHistogram::FactoryGet( std::string("Instant.SessionStorageNamespace") + (extended_enabled ? "_Extended" : "_Instant"), base::Histogram::kUmaTargetedHistogramFlag); const content::SessionStorageNamespaceMap& session_storage_map1 = - tab1->web_contents()->GetController().GetSessionStorageNamespaceMap(); + tab1->GetController().GetSessionStorageNamespaceMap(); const content::SessionStorageNamespaceMap& session_storage_map2 = - tab2->web_contents()->GetController().GetSessionStorageNamespaceMap(); + tab2->GetController().GetSessionStorageNamespaceMap(); bool is_session_storage_the_same = session_storage_map1.size() == session_storage_map2.size(); if (is_session_storage_the_same) { @@ -90,7 +90,7 @@ string16 Normalize(const string16& str) { } bool NormalizeAndStripPrefix(string16* text, const string16& prefix) { - const string16 norm_prefix = Normalize(prefix); + string16 norm_prefix = Normalize(prefix); string16 norm_text = Normalize(*text); if (norm_prefix.size() <= norm_text.size() && norm_text.compare(0, norm_prefix.size(), norm_prefix) == 0) { @@ -111,9 +111,8 @@ gfx::NativeView GetViewGainingFocus(gfx::NativeView view_gaining_focus) { views::FocusManager* focus_manager = widget->GetFocusManager(); if (focus_manager && focus_manager->is_changing_focus() && focus_manager->GetFocusedView() && - focus_manager->GetFocusedView()->GetWidget()) { + focus_manager->GetFocusedView()->GetWidget()) return focus_manager->GetFocusedView()->GetWidget()->GetNativeView(); - } } #endif return view_gaining_focus; @@ -149,10 +148,12 @@ InstantController::InstantController(chrome::BrowserInstantController* browser, extended_enabled_(extended_enabled), instant_enabled_(false), model_(ALLOW_THIS_IN_INITIALIZER_LIST(this)), + last_omnibox_text_has_inline_autocompletion_(false), last_verbatim_(false), last_transition_type_(content::PAGE_TRANSITION_LINK), last_match_was_search_(false), - is_omnibox_focused_(false) { + is_omnibox_focused_(false), + allow_preview_to_show_search_suggestions_(false) { } InstantController::~InstantController() { @@ -161,26 +162,26 @@ InstantController::~InstantController() { bool InstantController::Update(const AutocompleteMatch& match, const string16& user_text, const string16& full_text, - const bool verbatim, - const bool user_input_in_progress, - const bool omnibox_popup_is_open) { + size_t selection_start, + size_t selection_end, + bool verbatim, + bool user_input_in_progress, + bool omnibox_popup_is_open) { if (!extended_enabled_ && !instant_enabled_) return false; DVLOG(1) << "Update: " << AutocompleteMatch::TypeToString(match.type) << " user_text='" << user_text << "' full_text='" << full_text << "'" - << " verbatim=" << verbatim << " typing=" << user_input_in_progress - << " popup=" << omnibox_popup_is_open; + << " selection_start=" << selection_start << " selection_end=" + << selection_end << " verbatim=" << verbatim << " typing=" + << user_input_in_progress << " popup=" << omnibox_popup_is_open; // If the popup is open, the user has to be typing. 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; - - // If there's inline autocompletion, the query has to be verbatim. - DCHECK(user_text == full_text || verbatim) << user_text << "|" << full_text; + DCHECK(omnibox_popup_is_open || user_text.empty() || user_text == full_text) + << 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; @@ -197,108 +198,134 @@ bool InstantController::Update(const AutocompleteMatch& match, if (!extended_enabled_) search_mode_.mode = chrome::search::Mode::MODE_DEFAULT; - // If there's no active tab, the browser is closing. - const TabContents* const active_tab = browser_->GetActiveTabContents(); - if (!active_tab) { - Hide(true); + last_match_was_search_ = AutocompleteMatch::IsSearchType(match.type) && + !user_text.empty(); + + if (!ResetLoaderForMatch(match)) { + HideLoader(); return false; } - // Legend: OPIO == |omnibox_popup_is_open|, UIIP = |user_input_in_progress|. - // - // # OPIO UIIP full_text Notes - // - ---- ---- --------- ----- - // 1 no no blank } Navigation, or user hit Escape. |full_text| is - // 2 no no non-blank } blank if the page is NTP, non-blank otherwise. - // - // 3 no yes blank User backspaced away all omnibox text. - // - // 4 no yes non-blank User switched to a tab with a partial query. - // - // 5 yes no blank } Impossible. DCHECK()ed above. - // 6 yes no non-blank } - // - // 7 yes yes blank User typed a "?" into the omnibox. - // - // 8 yes yes non-blank User typed text into the omnibox. - // - // In non-extended mode, #1 to #7 call Hide(). #8 calls loader_->Update(). - // - // 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 calls - // Hide() unless on the NTP _and_ sends a blank query; otherwise #3 and #7 - // don't Hide(), but send a blank query to Update(). #8 calls Update(). - if (extended_enabled_) { if (!omnibox_popup_is_open) { - if (!full_text.empty() || - (user_input_in_progress && !search_mode_.is_origin_ntp())) { - Hide(true); - return false; + if (!user_input_in_progress) { + // If the user isn't typing and the omnibox popup is closed, it means a + // regular navigation, tab-switch or the user hitting Escape. + if (instant_tab_) { + // The user is on a search results page. It may be showing results for + // a partial query the user typed before they hit Escape. Send the + // omnibox text to the page to restore the original results. + // + // In a tab switch, |instant_tab_| won't have updated yet, so it may + // be pointing to the previous tab (which was a search results page). + // Ensure we don't send the omnibox text to a random webpage (the new + // tab), by comparing the old and new WebContents. + if (instant_tab_->contents() == browser_->GetActiveWebContents()) + instant_tab_->Submit(full_text); + } else if (!full_text.empty()) { + // If |full_text| is empty, the user is on the NTP. The preview may + // be showing custom NTP content; hide only if that's not the case. + HideLoader(); + } + } else if (full_text.empty()) { + // The user is typing, and backspaced away all omnibox text. Clear + // |last_omnibox_text_| so that we don't attempt to set suggestions. + last_omnibox_text_.clear(); + last_suggestion_ = InstantSuggestion(); + if (instant_tab_) { + // On a search results page, tell it to clear old results. + instant_tab_->Update(string16(), 0, 0, true); + } else if (search_mode_.is_origin_ntp()) { + // On the NTP, tell the preview to clear old results. Don't hide the + // preview so it can show a blank page or logo if it wants. + loader_->Update(string16(), 0, 0, true); + } else { + HideLoader(); + } + } else { + // The user switched to a tab with partial text already in the omnibox. + HideLoader(); + + // The new tab may or may not be a search results page; we don't know + // since SearchModeChanged() hasn't been called yet. If it later turns + // out to be, we should store |full_text| now, so that if the user hits + // Enter, we'll send the correct query to instant_tab_->Submit(). If the + // partial text is not a query (|last_match_was_search_| is false), we + // won't Submit(), so no need to worry about that. + last_omnibox_text_ = full_text; + last_suggestion_ = InstantSuggestion(); } - if (!user_input_in_progress && full_text.empty()) - return false; + return false; + } else if (full_text.empty()) { + // The user typed a solitary "?". Same as the backspace case above. + last_omnibox_text_.clear(); + last_suggestion_ = InstantSuggestion(); + if (instant_tab_) + instant_tab_->Update(string16(), 0, 0, true); + else if (search_mode_.is_origin_ntp()) + loader_->Update(string16(), 0, 0, true); + else + HideLoader(); + 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()) - Hide(true); + // In the non-extended case, hide the preview as long as the user isn't + // actively typing a non-empty query. However, Update() can be called if the + // user clicks the preview while composing text with an IME, so don't hide + // if the mouse is down, since we'll commit on mouse up later. + if (!loader_ || !loader_->is_pointer_down_from_activate()) + HideLoader(); 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; - } + last_omnibox_text_has_inline_autocompletion_ = user_text != full_text; // 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; - if (last_suggestion_.behavior == INSTANT_COMPLETE_NEVER) { - if (StartsWith(last_user_text_, user_text, false) && !user_text.empty()) { + if (last_suggestion_.behavior == INSTANT_COMPLETE_NEVER && + !last_omnibox_text_has_inline_autocompletion_) { + if (StartsWith(last_omnibox_text_, full_text, false)) { // The user is backspacing away characters. - last_suggestion_.text.insert(0, last_user_text_, user_text.size(), - last_user_text_.size() - user_text.size()); + last_suggestion_.text.insert(0, last_omnibox_text_, full_text.size(), + last_omnibox_text_.size() - full_text.size()); reused_suggestion = true; - } else if (StartsWith(user_text, last_user_text_, false)) { + } else if (StartsWith(full_text, last_omnibox_text_, false)) { // The user is typing forward. Normalize any added characters. reused_suggestion = NormalizeAndStripPrefix(&last_suggestion_.text, - string16(user_text, last_user_text_.size())); + string16(full_text, last_omnibox_text_.size())); } } - - last_user_text_ = user_text; - last_full_text_ = full_text; - last_verbatim_ = verbatim; - if (!reused_suggestion) last_suggestion_ = InstantSuggestion(); + last_omnibox_text_ = full_text; + + if (!extended_enabled_) { + // In non-extended mode, the query is verbatim if there's any selection + // (including inline autocompletion) or if the cursor is not at the end. + verbatim = verbatim || selection_start != selection_end || + selection_start != full_text.size(); + } + last_verbatim_ = verbatim; + last_transition_type_ = match.transition; - last_match_was_search_ = match_is_search; url_for_history_ = match.destination_url; - // Store the first interaction time for use with latency histograms. - if (first_interaction_time_.is_null()) - first_interaction_time_ = base::Time::Now(); - // Allow search suggestions. In extended mode, SearchModeChanged() will set // this, but it's not called in non-extended mode, so fake it. if (!extended_enabled_) search_mode_.mode = chrome::search::Mode::MODE_SEARCH_SUGGESTIONS; - loader_->Update(extended_enabled_ ? user_text : full_text, verbatim); + if (instant_tab_) { + instant_tab_->Update(user_text, selection_start, selection_end, verbatim); + } else { + if (first_interaction_time_.is_null()) + first_interaction_time_ = base::Time::Now(); + allow_preview_to_show_search_suggestions_ = true; + loader_->Update(extended_enabled_ ? user_text : full_text, + selection_start, selection_end, verbatim); + } content::NotificationService::current()->Notify( chrome::NOTIFICATION_INSTANT_CONTROLLER_UPDATED, @@ -312,7 +339,7 @@ bool InstantController::Update(const AutocompleteMatch& match, // Though we may have handled a URL match above, we return false here, so that // omnibox prerendering can kick in. TODO(sreeram): Remove this (and always // return true) once we are able to commit URLs as well. - return match_is_search; + return last_match_was_search_; } // TODO(tonyg): This method only fires when the omnibox bounds change. It also @@ -340,7 +367,7 @@ void InstantController::HandleAutocompleteResults( if (!extended_enabled_) return; - if (!GetPreviewContents()) + if (!instant_tab_ && !loader_) return; DVLOG(1) << "AutocompleteResults:"; @@ -362,22 +389,29 @@ void InstantController::HandleAutocompleteResults( } } - loader_->SendAutocompleteResults(results); + if (instant_tab_) + instant_tab_->SendAutocompleteResults(results); + else + loader_->SendAutocompleteResults(results); } bool InstantController::OnUpOrDownKeyPressed(int count) { if (!extended_enabled_) return false; - if (!GetPreviewContents()) + if (!instant_tab_ && !loader_) return false; - loader_->OnUpOrDownKeyPressed(count); + if (instant_tab_) + instant_tab_->UpOrDownKeyPressed(count); + else + loader_->UpOrDownKeyPressed(count); + return true; } -TabContents* InstantController::GetPreviewContents() const { - return loader_ ? loader_->preview_contents() : NULL; +content::WebContents* InstantController::GetPreviewContents() const { + return loader_ ? loader_->contents() : NULL; } bool InstantController::IsCurrent() const { @@ -388,11 +422,29 @@ bool InstantController::CommitIfCurrent(InstantCommitType type) { if (!extended_enabled_ && !instant_enabled_) return false; + DVLOG(1) << "CommitIfCurrent: type=" << type << " last_omnibox_text_='" + << last_omnibox_text_ << "' last_match_was_search_=" + << last_match_was_search_ << " instant_tab_=" << instant_tab_; + + // If we are on an already committed search results page, send a submit event + // to the page, but otherwise, nothing else to do. + if (instant_tab_) { + if (last_match_was_search_ && type == INSTANT_COMMIT_PRESSED_ENTER) { + instant_tab_->Submit(last_omnibox_text_); + return true; + } + return false; + } + if (!IsCurrent()) return false; - DVLOG(1) << "CommitIfCurrent"; - TabContents* preview = loader_->ReleasePreviewContents(type, last_full_text_); + if (type == INSTANT_COMMIT_FOCUS_LOST) + loader_->Cancel(last_omnibox_text_); + else + loader_->Submit(last_omnibox_text_); + + content::WebContents* preview = loader_->ReleaseContents(); if (extended_enabled_) { // Consider what's happening: @@ -407,16 +459,16 @@ bool InstantController::CommitIfCurrent(InstantCommitType type) { // TODO(samarth,beaudoin): Instead of this hack, we should add a new field // to NavigationEntry to keep track of what the correct query, if any, is. content::NavigationEntry* entry = - preview->web_contents()->GetController().GetVisibleEntry(); + preview->GetController().GetVisibleEntry(); std::string url = entry->GetVirtualURL().spec(); if (!google_util::IsInstantExtendedAPIGoogleSearchUrl(url) && google_util::IsGoogleDomainUrl(url, google_util::ALLOW_SUBDOMAIN, google_util::ALLOW_NON_STANDARD_PORTS)) { entry->SetVirtualURL(GURL( url + "#q=" + - net::EscapeQueryParamValue(UTF16ToUTF8(last_full_text_), true))); - chrome::search::SearchTabHelper::FromWebContents( - preview->web_contents())->NavigationEntryUpdated(); + net::EscapeQueryParamValue(UTF16ToUTF8(last_omnibox_text_), true))); + chrome::search::SearchTabHelper::FromWebContents(preview)-> + NavigationEntryUpdated(); } } @@ -426,13 +478,12 @@ bool InstantController::CommitIfCurrent(InstantCommitType type) { const history::HistoryAddPageArgs& last_navigation = loader_->last_navigation(); if (!last_navigation.url.is_empty()) { - content::NavigationEntry* entry = - preview->web_contents()->GetController().GetActiveEntry(); + content::NavigationEntry* entry = preview->GetController().GetActiveEntry(); DCHECK_EQ(last_navigation.url, entry->GetURL()); // Add the page to history. HistoryTabHelper* history_tab_helper = - HistoryTabHelper::FromWebContents(preview->web_contents()); + HistoryTabHelper::FromWebContents(preview); history_tab_helper->UpdateHistoryForNavigation(last_navigation); // Update the page title. @@ -441,34 +492,38 @@ bool InstantController::CommitIfCurrent(InstantCommitType type) { // Add a fake history entry with a non-Instant search URL, so that search // terms extraction (for autocomplete history matches) works. - if (HistoryService* history = HistoryServiceFactory::GetForProfile( - preview->profile(), Profile::EXPLICIT_ACCESS)) { + HistoryService* history = HistoryServiceFactory::GetForProfile( + Profile::FromBrowserContext(preview->GetBrowserContext()), + Profile::EXPLICIT_ACCESS); + if (history) { history->AddPage(url_for_history_, base::Time::Now(), NULL, 0, GURL(), history::RedirectList(), last_transition_type_, history::SOURCE_BROWSED, false); } - preview->web_contents()->GetController().PruneAllButActive(); + preview->GetController().PruneAllButActive(); if (type != INSTANT_COMMIT_PRESSED_ALT_ENTER) { - const TabContents* active_tab = browser_->GetActiveTabContents(); + content::WebContents* active_tab = browser_->GetActiveWebContents(); AddSessionStorageHistogram(extended_enabled_, active_tab, preview); - preview->web_contents()->GetController().CopyStateFromAndPrune( - &active_tab->web_contents()->GetController()); + preview->GetController().CopyStateFromAndPrune( + &active_tab->GetController()); } - DeleteLoader(); - // Browser takes ownership of the preview. browser_->CommitInstant(preview, type == INSTANT_COMMIT_PRESSED_ALT_ENTER); content::NotificationService::current()->Notify( chrome::NOTIFICATION_INSTANT_COMMITTED, - content::Source<content::WebContents>(preview->web_contents()), + content::Source<content::WebContents>(preview), content::NotificationService::NoDetails()); + // Hide explicitly. See comments in HideLoader() for why. model_.SetPreviewState(chrome::search::Mode(), 0, INSTANT_SIZE_PERCENT); + // Delay deletion as we could've gotten here from an InstantLoader method. + MessageLoop::current()->DeleteSoon(FROM_HERE, loader_.release()); + // Try to create another loader immediately so that it is ready for the next // user interaction. CreateDefaultLoader(); @@ -492,14 +547,14 @@ void InstantController::OmniboxLostFocus(gfx::NativeView view_gaining_focus) { } #if defined(OS_MACOSX) - if (!loader_->IsPointerDownFromActivate()) - Hide(true); + if (!loader_->is_pointer_down_from_activate()) + HideLoader(); #else if (IsViewInContents(GetViewGainingFocus(view_gaining_focus), - GetPreviewContents()->web_contents())) + loader_->contents())) CommitIfCurrent(INSTANT_COMMIT_FOCUS_LOST); else - Hide(true); + HideLoader(); #endif } @@ -510,8 +565,7 @@ void InstantController::OmniboxGotFocus() { if (!extended_enabled_ && !instant_enabled_) return; - if (!GetPreviewContents()) - CreateDefaultLoader(); + CreateDefaultLoader(); } void InstantController::SearchModeChanged( @@ -523,18 +577,15 @@ void InstantController::SearchModeChanged( DVLOG(1) << "SearchModeChanged: [origin:mode] " << old_mode.origin << ":" << old_mode.mode << " to " << new_mode.origin << ":" << new_mode.mode; - search_mode_ = new_mode; - if (new_mode.is_search_suggestions()) { - // The preview is showing NTP content, but it's not appropriate anymore. - if (model_.mode().is_ntp() && !new_mode.is_origin_ntp()) - Hide(false); - } else { - Hide(true); - } + search_mode_ = new_mode; + if (!new_mode.is_search_suggestions()) + HideLoader(); - if (GetPreviewContents()) + if (loader_) loader_->SearchModeChanged(new_mode); + + ResetInstantTab(); } void InstantController::ActiveTabChanged() { @@ -543,32 +594,29 @@ void InstantController::ActiveTabChanged() { DVLOG(1) << "ActiveTabChanged"; - // By this time, SearchModeChanged() should've been called, so we only need to - // handle the case when the search mode does NOT change, as in the case of - // going from search_suggestions to search_suggestions (i.e., partial queries - // on both old and new tabs). - if (search_mode_.is_search_suggestions() && - model_.mode().is_search_suggestions()) - Hide(false); + // When switching tabs, always hide the preview, except if it's showing NTP + // content, and the new tab is also an NTP. + if (!search_mode_.is_ntp() || !model_.mode().is_ntp()) + HideLoader(); + + if (extended_enabled_) + ResetInstantTab(); } void InstantController::SetInstantEnabled(bool instant_enabled) { DVLOG(1) << "SetInstantEnabled: " << instant_enabled; instant_enabled_ = instant_enabled; - if (extended_enabled_) { - // Reset the loader whenever the Instant pref changes. - DeleteLoader(); + HideInternal(); + loader_.reset(); + if (extended_enabled_ || instant_enabled_) CreateDefaultLoader(); - } else if (!instant_enabled_) { - DeleteLoader(); - } } void InstantController::ThemeChanged(const ThemeBackgroundInfo& theme_info) { if (!extended_enabled_) return; - if (GetPreviewContents()) + if (loader_) loader_->SendThemeBackgroundInfo(theme_info); } @@ -576,17 +624,28 @@ void InstantController::ThemeAreaHeightChanged(int height) { if (!extended_enabled_) return; - if (GetPreviewContents()) + if (loader_) loader_->SendThemeAreaHeight(height); } void InstantController::SetSuggestions( - InstantLoader* loader, + const content::WebContents* contents, const std::vector<InstantSuggestion>& suggestions) { DVLOG(1) << "SetSuggestions"; - if (loader_ != loader || !search_mode_.is_search_suggestions()) + + // Ignore if we are not currently accepting search suggestions. + if (!search_mode_.is_search_suggestions() || last_omnibox_text_.empty()) return; + // Ignore if the message is from an unexpected source. + if (instant_tab_) { + if (instant_tab_->contents() != contents) + return; + } else if (!loader_ || loader_->contents() != contents || + !allow_preview_to_show_search_suggestions_) { + return; + } + InstantSuggestion suggestion; if (!suggestions.empty()) suggestion = suggestions[0]; @@ -596,9 +655,7 @@ void InstantController::SetSuggestions( // suggestion (so that we don't inadvertently cause the preview to change // what it's showing, as the user arrows up/down through the page-provided // suggestions). So, update these state variables here. - last_full_text_ = suggestion.text; - last_user_text_.clear(); - last_verbatim_ = true; + last_omnibox_text_ = suggestion.text; last_suggestion_ = InstantSuggestion(); last_match_was_search_ = suggestion.type == INSTANT_SUGGESTION_SEARCH; DVLOG(1) << "SetReplaceSuggestion: text='" << suggestion.text << "'" @@ -615,10 +672,10 @@ void InstantController::SetSuggestions( if (!GURL(suggestion.text).is_valid()) suggestion = InstantSuggestion(); } - } else if (StartsWith(suggestion.text, last_user_text_, true)) { + } else if (StartsWith(suggestion.text, last_omnibox_text_, true)) { // The user typed an exact prefix of the suggestion. - suggestion.text.erase(0, last_user_text_.size()); - } else if (!NormalizeAndStripPrefix(&suggestion.text, last_user_text_)) { + suggestion.text.erase(0, last_omnibox_text_.size()); + } else if (!NormalizeAndStripPrefix(&suggestion.text, last_omnibox_text_)) { // Unicode normalize and case-fold the user text and suggestion. If the // user text is a prefix, suggest the normalized, case-folded completion; // for instance, if the user types 'i' and the suggestion is 'INSTANT', @@ -627,14 +684,10 @@ void InstantController::SetSuggestions( suggestion = InstantSuggestion(); } - // If the omnibox is blank, this suggestion is for an older query. Ignore. - if (last_user_text_.empty()) - suggestion = InstantSuggestion(); - // Don't suggest gray text if there already was inline autocompletion. // http://crbug.com/162303 if (suggestion.behavior == INSTANT_COMPLETE_NEVER && - last_user_text_ != last_full_text_) + last_omnibox_text_has_inline_autocompletion_) suggestion = InstantSuggestion(); // Don't allow inline autocompletion if the query was verbatim. @@ -651,93 +704,94 @@ void InstantController::SetSuggestions( } } - // Extended mode pages will show() when ready. + // Extended mode pages will call ShowLoader() when they are ready. if (!extended_enabled_) - Show(INSTANT_SHOWN_QUERY_SUGGESTIONS, 100, INSTANT_SIZE_PERCENT); + ShowLoader(INSTANT_SHOWN_QUERY_SUGGESTIONS, 100, INSTANT_SIZE_PERCENT); } -void InstantController::CommitInstantLoader(InstantLoader* loader) { - if (loader_ == loader) - CommitIfCurrent(INSTANT_COMMIT_FOCUS_LOST); +void InstantController::InstantSupportDetermined( + const content::WebContents* contents, + bool supports_instant) { + if (instant_tab_ && instant_tab_->contents() == contents) { + if (!supports_instant) + MessageLoop::current()->DeleteSoon(FROM_HERE, instant_tab_.release()); + return; + } + + if (loader_ && loader_->contents() == contents) { + if (supports_instant) { + blacklisted_urls_.erase(loader_->instant_url()); + } else { + ++blacklisted_urls_[loader_->instant_url()]; + HideInternal(); + delete loader_->ReleaseContents(); + MessageLoop::current()->DeleteSoon(FROM_HERE, loader_.release()); + CreateDefaultLoader(); + } + content::NotificationService::current()->Notify( + chrome::NOTIFICATION_INSTANT_SUPPORT_DETERMINED, + content::Source<InstantController>(this), + content::NotificationService::NoDetails()); + } } -void InstantController::ShowInstantPreview(InstantLoader* loader, - InstantShownReason reason, +void InstantController::ShowInstantPreview(InstantShownReason reason, int height, InstantSizeUnits units) { - if (loader_ == loader && extended_enabled_) - Show(reason, height, units); -} - -void InstantController::InstantSupportDetermined(InstantLoader* loader, - bool supports_instant) { - if (supports_instant) { - blacklisted_urls_.erase(loader->instant_url()); - } else { - ++blacklisted_urls_[loader->instant_url()]; - if (loader_ == loader) - DeleteLoader(); - } - - content::NotificationService::current()->Notify( - chrome::NOTIFICATION_INSTANT_SUPPORT_DETERMINED, - content::Source<InstantController>(this), - content::NotificationService::NoDetails()); + if (extended_enabled_) + ShowLoader(reason, height, units); } -void InstantController::SwappedTabContents(InstantLoader* loader) { - if (loader_ == loader) - model_.SetPreviewContents(GetPreviewContents()); +void InstantController::SwappedWebContents() { + model_.SetPreviewContents(GetPreviewContents()); } -void InstantController::InstantLoaderContentsFocused(InstantLoader* loader) { +void InstantController::InstantLoaderContentsFocused() { #if defined(USE_AURA) // On aura the omnibox only receives a focus lost if we initiate the focus // change. This does that. - if (loader_ == loader && !model_.mode().is_default()) + if (!model_.mode().is_default()) browser_->InstantPreviewFocused(); #endif } bool InstantController::ResetLoader(const TemplateURL* template_url, - const TabContents* active_tab) { + const content::WebContents* active_tab) { std::string instant_url; if (!GetInstantURL(template_url, &instant_url)) return false; - if (GetPreviewContents() && loader_->instant_url() != instant_url) - DeleteLoader(); - - if (!GetPreviewContents()) { - loader_.reset(new InstantLoader(this, instant_url, active_tab)); - loader_->Init(); + if (loader_ && loader_->instant_url() == instant_url) + return true; - // Ensure the searchbox API has the correct initial state. - if (extended_enabled_) { - browser_->UpdateThemeInfoForPreview(); - loader_->SetDisplayInstantResults(instant_enabled_); - loader_->SearchModeChanged(search_mode_); - } + HideInternal(); + loader_.reset(new InstantLoader(this, instant_url)); + loader_->InitContents(active_tab); - // Reset the loader timer. - stale_loader_timer_.Start( - FROM_HERE, - base::TimeDelta::FromMilliseconds(kStaleLoaderTimeoutMS), this, - &InstantController::OnStaleLoader); + // Ensure the searchbox API has the correct initial state. + if (extended_enabled_) { + browser_->UpdateThemeInfoForPreview(); + loader_->SetDisplayInstantResults(instant_enabled_); + loader_->SearchModeChanged(search_mode_); } + // Restart the stale loader timer. + stale_loader_timer_.Start(FROM_HERE, + base::TimeDelta::FromMilliseconds(kStaleLoaderTimeoutMS), this, + &InstantController::OnStaleLoader); + return true; } bool InstantController::CreateDefaultLoader() { // If there's no active tab, the browser is closing. - const TabContents* active_tab = browser_->GetActiveTabContents(); + const content::WebContents* active_tab = browser_->GetActiveWebContents(); if (!active_tab) return false; - const TemplateURL* template_url = - TemplateURLServiceFactory::GetForProfile(active_tab->profile())-> - GetDefaultSearchProvider(); + const TemplateURL* template_url = TemplateURLServiceFactory::GetForProfile( + Profile::FromBrowserContext(active_tab->GetBrowserContext()))-> + GetDefaultSearchProvider(); return ResetLoader(template_url, active_tab); } @@ -748,65 +802,87 @@ void InstantController::OnStaleLoader() { // omnibox loses focus. if (!stale_loader_timer_.IsRunning() && !is_omnibox_focused_ && model_.mode().is_default()) { - DeleteLoader(); + loader_.reset(); CreateDefaultLoader(); } } -void InstantController::DeleteLoader() { - // Clear all state, except |last_transition_type_| as it's used during commit. - last_user_text_.clear(); - last_full_text_.clear(); - last_verbatim_ = false; - last_suggestion_ = InstantSuggestion(); - last_match_was_search_ = false; - if (!extended_enabled_) - search_mode_.mode = chrome::search::Mode::MODE_DEFAULT; - omnibox_bounds_ = gfx::Rect(); - last_omnibox_bounds_ = gfx::Rect(); - update_bounds_timer_.Stop(); - stale_loader_timer_.Stop(); - url_for_history_ = GURL(); - first_interaction_time_ = base::Time(); - if (GetPreviewContents()) { - model_.SetPreviewState(chrome::search::Mode(), 0, INSTANT_SIZE_PERCENT); - loader_->CleanupPreviewContents(); +void InstantController::ResetInstantTab() { + if (search_mode_.is_origin_search()) { + content::WebContents* active_tab = browser_->GetActiveWebContents(); + if (!instant_tab_ || active_tab != instant_tab_->contents()) { + instant_tab_.reset(new InstantTab(this, active_tab)); + instant_tab_->Init(); + } + + // Hide the |loader_| since we are now using |instant_tab_| instead. + HideLoader(); + } else { + instant_tab_.reset(); } +} - // Schedule the deletion for later, since we may have gotten here from a call - // within a |loader_| method (i.e., it's still on the stack). If we deleted - // the loader immediately, things would still be fine so long as the caller - // doesn't access any instance members after we return, but why rely on that? - MessageLoop::current()->DeleteSoon(FROM_HERE, loader_.release()); +bool InstantController::ResetLoaderForMatch(const AutocompleteMatch& match) { + // If we are on a search results page, we'll use that instead of a loader. + // TODO(sreeram): If |instant_tab_|'s URL is not the same as the instant_url + // of |match|, we shouldn't use the committed tab. + if (instant_tab_) + return true; + + // If there's no active tab, the browser is closing. + const content::WebContents* active_tab = browser_->GetActiveWebContents(); + if (!active_tab) + return false; + + // Try to create a loader for the instant_url in the TemplateURL of |match|. + const TemplateURL* template_url = match.GetTemplateURL( + Profile::FromBrowserContext(active_tab->GetBrowserContext()), false); + if (ResetLoader(template_url, active_tab)) + return true; + + // In non-extended mode, stop if we couldn't get a loader for the |match|. + if (!extended_enabled_) + return false; + + // If the match is a query, it is for a non-Instant search engine; stop. + if (last_match_was_search_) + return false; + + // The match is a URL, or a blank query. Try the default search engine. + return CreateDefaultLoader(); } -void InstantController::Hide(bool clear_query) { - DVLOG(1) << "Hide: clear_query=" << clear_query; +void InstantController::HideLoader() { + HideInternal(); + OnStaleLoader(); +} - // The only time when the preview is not already in the desired MODE_DEFAULT - // state and GetPreviewContents() returns NULL is when we are in the commit - // path. In that case, don't change the state just yet; otherwise we may - // cause the preview to hide unnecessarily. Instead, the state will be set - // correctly after the commit is done. - if (GetPreviewContents()) - model_.SetPreviewState(chrome::search::Mode(), 0, INSTANT_SIZE_PERCENT); +void InstantController::HideInternal() { + DVLOG(1) << "Hide"; - // Clear the first interaction timestamp for later use. - first_interaction_time_ = base::Time(); + // If GetPreviewContents() returns NULL, either we're already in the desired + // MODE_DEFAULT state, or we're in the commit path. For the latter, don't + // change the state just yet; else we may hide the preview unnecessarily. + // Instead, the state will be set correctly after the commit is done. + if (GetPreviewContents()) { + model_.SetPreviewState(chrome::search::Mode(), 0, INSTANT_SIZE_PERCENT); + allow_preview_to_show_search_suggestions_ = false; - if (clear_query) { - if (GetPreviewContents() && !last_full_text_.empty()) - loader_->Update(string16(), true); - last_user_text_.clear(); - last_full_text_.clear(); + // Send a message asking the preview to clear out old results. + loader_->Update(string16(), 0, 0, true); } - OnStaleLoader(); + // Clear the first interaction timestamp for later use. + first_interaction_time_ = base::Time(); } -void InstantController::Show(InstantShownReason reason, - int height, - InstantSizeUnits units) { +void InstantController::ShowLoader(InstantShownReason reason, + int height, + InstantSizeUnits units) { + // If we are on a committed search results page, the |loader_| is not in use. + if (instant_tab_) + return; + DVLOG(1) << "Show: reason=" << reason << " height=" << height << " units=" << units; @@ -814,29 +890,33 @@ void InstantController::Show(InstantShownReason reason, if (reason == INSTANT_SHOWN_CUSTOM_NTP_CONTENT && !search_mode_.is_ntp()) return; - // Must have updated omnibox after most recent Hide() to show suggestions. + // Must have updated omnibox after the last HideLoader() to show suggestions. if (reason == INSTANT_SHOWN_QUERY_SUGGESTIONS && - !search_mode_.is_search_suggestions()) + !allow_preview_to_show_search_suggestions_) + return; + + // The page is trying to hide itself. Hide explicitly (i.e., don't use + // HideLoader()) so that it can change its mind. + if (height == 0) { + model_.SetPreviewState(chrome::search::Mode(), 0, INSTANT_SIZE_PERCENT); return; + } - // If the preview is being shown because of the first set of suggestions to - // arrive for this query editing session, record a histogram value. + // If the preview is being shown for the first time since the user started + // typing, record a histogram value. if (!first_interaction_time_.is_null() && model_.mode().is_default()) { base::TimeDelta delta = base::Time::Now() - first_interaction_time_; UMA_HISTOGRAM_TIMES("Instant.TimeToFirstShow", delta); } // Show at 100% height except in the following cases: - // - Instant is disabled. In this case the page should only ever show - // a dropdown and we should always accept its height. - // - The page wants to hide (height=0). + // - Instant is disabled. The page needs to be able to show only a dropdown. // - The page wants to show custom NTP content. // - The page is over a website other than search or an NTP, and is not // already showing at 100% height. - const bool is_full_height = - model_.height() == 100 && model_.height_units() == INSTANT_SIZE_PERCENT; - if (height == 0 || !instant_enabled_ || - reason == INSTANT_SHOWN_CUSTOM_NTP_CONTENT || + bool is_full_height = model_.height() == 100 && + model_.height_units() == INSTANT_SIZE_PERCENT; + if (!instant_enabled_ || reason == INSTANT_SHOWN_CUSTOM_NTP_CONTENT || (search_mode_.is_origin_default() && !is_full_height)) model_.SetPreviewState(search_mode_, height, units); else @@ -844,8 +924,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_->is_pointer_down_from_activate()) return; last_omnibox_bounds_ = omnibox_bounds_; @@ -899,8 +979,8 @@ bool InstantController::GetInstantURL(const TemplateURL* template_url, return false; if (!url_obj.SchemeIsSecure()) { - const std::string new_scheme = "https"; - const std::string new_port = "443"; + std::string new_scheme = "https"; + std::string new_port = "443"; GURL::Replacements secure; secure.SetSchemeStr(new_scheme); secure.SetPortStr(new_port); diff --git a/chrome/browser/instant/instant_controller.h b/chrome/browser/instant/instant_controller.h index 436f986..941dd15 100644 --- a/chrome/browser/instant/instant_controller.h +++ b/chrome/browser/instant/instant_controller.h @@ -27,14 +27,17 @@ struct AutocompleteMatch; class AutocompleteProvider; class InstantLoader; -class TabContents; +class InstantTab; class TemplateURL; -struct ThemeBackgroundInfo; namespace chrome { class BrowserInstantController; } +namespace content { +class WebContents; +} + // InstantController maintains a WebContents that is intended to give a preview // of search suggestions and results. InstantController is owned by Browser via // BrowserInstantController. @@ -53,6 +56,8 @@ class InstantController { bool Update(const AutocompleteMatch& match, const string16& user_text, const string16& full_text, + size_t selection_start, + size_t selection_end, bool verbatim, bool user_input_in_progress, bool omnibox_popup_is_open); @@ -69,10 +74,8 @@ class InstantController { // handled the key press. bool OnUpOrDownKeyPressed(int count); - // The preview TabContents. May be NULL if ReleasePreviewContents() has been - // called, with no subsequent successful call to Update(). InstantController - // retains ownership of the object. - TabContents* GetPreviewContents() const; + // The preview WebContents. May be NULL. InstantController retains ownership. + content::WebContents* GetPreviewContents() const; // Returns true if the Instant preview can be committed now. bool IsCurrent() const; @@ -89,22 +92,22 @@ class InstantController { void OmniboxGotFocus(); // The search mode in the active tab has changed. Pass the message down to - // the loader which will notify the renderer. + // the loader which will notify the renderer. Create |instant_tab_| if the + // |new_mode| reflects an Instant search results page. void SearchModeChanged(const chrome::search::Mode& old_mode, const chrome::search::Mode& new_mode); - // The user switched tabs. Hide the preview if needed. + // The user switched tabs. Hide the preview. Create |instant_tab_| if the + // newly active tab is an Instant search results page. void ActiveTabChanged(); // Sets whether Instant should show result previews. void SetInstantEnabled(bool instant_enabled); - // The theme has changed. Pass the message down to the loader which will - // notify the renderer. + // The theme has changed. Pass the message to the preview page. void ThemeChanged(const ThemeBackgroundInfo& theme_info); - // The theme area height has changed. Pass the message down to the loader - // which will notify the renderer. + // The theme area height has changed. Pass the message to the preview page. void ThemeAreaHeightChanged(int height); // Returns the transition type of the last AutocompleteMatch passed to Update. @@ -114,37 +117,30 @@ class InstantController { const InstantModel* model() const { return &model_; } - // Invoked by InstantLoader when it has suggested text. - void SetSuggestions(InstantLoader* loader, + // Invoked by the page when it has suggested text. + void SetSuggestions(const content::WebContents* contents, const std::vector<InstantSuggestion>& suggestions); - // Invoked by InstantLoader to commit the preview. - void CommitInstantLoader(InstantLoader* loader); + // Invoked by the page when its support for the Instant API is determined. + void InstantSupportDetermined(const content::WebContents* contents, + bool supports_instant); // Invoked by InstantLoader to request that the preview be shown. - void ShowInstantPreview(InstantLoader* loader, - InstantShownReason reason, + void ShowInstantPreview(InstantShownReason reason, int height, InstantSizeUnits units); - // Invoked by InstantLoader when it has determined whether or not the page - // supports the Instant API. - void InstantSupportDetermined(InstantLoader* loader, bool supports_instant); - - // Invoked by InstantLoader when it has swapped a different TabContents into + // Invoked by InstantLoader when it has swapped a different WebContents into // the preview, usually because a prerendered page was navigated to. - void SwappedTabContents(InstantLoader* loader); + void SwappedWebContents(); // Invoked by InstantLoader when the preview gains focus, usually due to the // user clicking on it. - void InstantLoaderContentsFocused(InstantLoader* loader); - -#if defined(UNIT_TEST) - // Accessors used only in tests. - InstantLoader* loader() const { return loader_.get(); } -#endif + void InstantLoaderContentsFocused(); private: + FRIEND_TEST_ALL_PREFIXES(InstantTest, OmniboxFocusLoadsInstant); + FRIEND_TEST_ALL_PREFIXES(InstantTest, NonInstantSearchProvider); FRIEND_TEST_ALL_PREFIXES(InstantTest, InstantLoaderRefresh); // Creates a new loader if necessary, using the instant_url property of the @@ -152,7 +148,7 @@ class InstantController { // time the loader was created). Returns false if the |template_url| doesn't // have a valid Instant URL; true otherwise. bool ResetLoader(const TemplateURL* template_url, - const TabContents* active_tab); + const content::WebContents* active_tab); // Ensures that the |loader_| uses the default Instant URL, recreating it if // necessary, and returns true. Returns false if the Instant URL could not be @@ -164,17 +160,27 @@ class InstantController { // deleted and recreated. Else the refresh is skipped. void OnStaleLoader(); - // Destroys the |loader_| and its preview contents. - void DeleteLoader(); + // If the active tab is an Instant search results page, sets |instant_tab_| to + // point to it. Else, deletes any existing |instant_tab_|. + void ResetInstantTab(); - // Hide the preview. If |clear_query| is true, clears query text and sends a - // an onchange event (with blank query) to the preview, telling it to clear - // out results for any old queries. - void Hide(bool clear_query); + // Called by Update() to ensure we have an Instant page that can process + // |match|. Returns true if we should continue with the Update(). + bool ResetLoaderForMatch(const AutocompleteMatch& match); - // Counterpart to Hide(). Asks the |browser_| to display the preview with - // the given |height|. - void Show(InstantShownReason reason, int height, InstantSizeUnits units); + // Hide the preview. Also sends an onchange event (with blank query) to the + // preview, telling it to clear out results for any old queries. + void HideLoader(); + + // Like HideLoader(), but doesn't call OnStaleLoader(). Use HideLoader() + // unless you are going to call loader_.reset() yourself subsequently. + void HideInternal(); + + // Counterpart to HideLoader(). Asks the |browser_| to display the preview + // with the given |height|. + void ShowLoader(InstantShownReason reason, + int height, + InstantSizeUnits units); // Send the omnibox dropdown bounds to the page. void SendBoundsToPage(); @@ -193,17 +199,27 @@ class InstantController { const bool extended_enabled_; bool instant_enabled_; + // The state of the preview page, i.e., the page owned by |loader_|. Ignored + // if |instant_tab_| is in use. InstantModel model_; + // The preview WebContents. scoped_ptr<InstantLoader> loader_; - // The most recent user_text passed to Update(). - string16 last_user_text_; + // A committed WebContents that supports Instant. If non-NULL, the |loader_| + // is guaranteed to be hidden and messages will be sent to this instead. + scoped_ptr<InstantTab> instant_tab_; - // The most recent full_text passed to Update(). - string16 last_full_text_; + // The most recent full_text passed to Update(). If empty, we'll not accept + // search suggestions from |loader_| or |instant_tab_|. + string16 last_omnibox_text_; - // The most recent verbatim passed to Update(). + // True if the last Update() had an inline autocompletion. Used only to make + // sure that we don't accidentally suggest gray text suggestion in that case. + bool last_omnibox_text_has_inline_autocompletion_; + + // The most recent verbatim passed to Update(). Used only to ensure that we + // don't accidentally suggest an inline autocompletion. bool last_verbatim_; // The most recent suggestion received from the page, minus any prefix that @@ -214,6 +230,7 @@ class InstantController { content::PageTransition last_transition_type_; // True if the last match passed to Update() was a search (versus a URL). + // Used to ensure that the preview page is committable. bool last_match_was_search_; // True if the omnibox is focused, false otherwise. @@ -245,13 +262,18 @@ class InstantController { // on Instant URLs. So, whenever the user commits an Instant search, we add // an equivalent non-Instant search URL to history, so that the search shows // up in autocomplete history matches. + // TODO(sreeram): Remove when http://crbug.com/155373 is fixed. GURL url_for_history_; // The timestamp at which query editing began. This value is used when the - // first set of suggestions is processed and cleared when the overlay is - // hidden. + // preview is showed and cleared when the preview is hidden. base::Time first_interaction_time_; + // Whether to allow the preview to show search suggestions. In general, the + // preview is allowed to show search suggestions whenever |search_mode_| is + // MODE_SEARCH_SUGGESTIONS, except in those cases where this is false. + bool allow_preview_to_show_search_suggestions_; + DISALLOW_COPY_AND_ASSIGN(InstantController); }; diff --git a/chrome/browser/instant/instant_loader.cc b/chrome/browser/instant/instant_loader.cc index 1eadd70..34fa5c0 100644 --- a/chrome/browser/instant/instant_loader.cc +++ b/chrome/browser/instant/instant_loader.cc @@ -6,7 +6,6 @@ #include "chrome/browser/content_settings/tab_specific_content_settings.h" #include "chrome/browser/instant/instant_controller.h" -#include "chrome/browser/profiles/profile.h" #include "chrome/browser/thumbnails/thumbnail_tab_helper.h" #include "chrome/browser/ui/blocked_content/blocked_content_tab_helper.h" #include "chrome/browser/ui/constrained_window_tab_helper.h" @@ -14,13 +13,11 @@ #include "chrome/browser/ui/tab_contents/core_tab_helper.h" #include "chrome/browser/ui/tab_contents/core_tab_helper_delegate.h" #include "chrome/browser/ui/tab_contents/tab_contents.h" -#include "chrome/common/render_messages.h" -#include "content/public/browser/navigation_entry.h" #include "content/public/browser/notification_source.h" #include "content/public/browser/notification_types.h" -#include "content/public/browser/render_view_host.h" #include "content/public/browser/render_widget_host_view.h" #include "content/public/browser/web_contents_delegate.h" +#include "ipc/ipc_message.h" namespace { @@ -47,19 +44,10 @@ class InstantLoaderUserData : public base::SupportsUserData::Data { class InstantLoader::WebContentsDelegateImpl : public ConstrainedWindowTabHelperDelegate, public CoreTabHelperDelegate, - public content::WebContentsDelegate, - public content::WebContentsObserver { + public content::WebContentsDelegate { public: explicit WebContentsDelegateImpl(InstantLoader* loader); - bool is_pointer_down_from_activate() const { - return is_pointer_down_from_activate_; - } - - // Start observing |web_contents| instead of whatever is currently being - // observed. If |web_contents| is NULL, effectively stops observing. - void ObserveContents(content::WebContents* web_contents); - private: // Overridden from ConstrainedWindowTabHelperDelegate: virtual bool ShouldFocusConstrainedWindow() OVERRIDE; @@ -83,47 +71,16 @@ class InstantLoader::WebContentsDelegateImpl virtual void DragEnded() OVERRIDE; virtual bool OnGoToEntryOffset(int offset) OVERRIDE; - // Overridden from content::WebContentsObserver: - virtual void DidFinishLoad( - int64 frame_id, - const GURL& validated_url, - bool is_main_frame, - content::RenderViewHost* render_view_host) OVERRIDE; - virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; - - // Message from renderer indicating the page has suggestions. - void OnSetSuggestions(int page_id, - const std::vector<InstantSuggestion>& suggestions); - - // Message from the renderer determining whether it supports the Instant API. - void OnInstantSupportDetermined(int page_id, bool result); - - // Message from the renderer requesting the preview be shown. - void OnShowInstantPreview(int page_id, - InstantShownReason reason, - int height, - InstantSizeUnits units); - - void CommitFromPointerReleaseIfNecessary(); - void MaybeSetAndNotifyInstantSupportDetermined(bool supports_instant); + void MaybeCommitFromPointerRelease(); InstantLoader* const loader_; - // True if the mouse or a touch pointer is down from an activate. - bool is_pointer_down_from_activate_; - DISALLOW_COPY_AND_ASSIGN(WebContentsDelegateImpl); }; InstantLoader::WebContentsDelegateImpl::WebContentsDelegateImpl( InstantLoader* loader) - : loader_(loader), - is_pointer_down_from_activate_(false) { -} - -void InstantLoader::WebContentsDelegateImpl::ObserveContents( - content::WebContents* web_contents) { - Observe(web_contents); + : loader_(loader) { } bool InstantLoader::WebContentsDelegateImpl::ShouldFocusConstrainedWindow() { @@ -136,8 +93,8 @@ bool InstantLoader::WebContentsDelegateImpl::ShouldFocusConstrainedWindow() { void InstantLoader::WebContentsDelegateImpl::SwapTabContents( content::WebContents* old_contents, content::WebContents* new_contents) { - // If this is being called, something is swapping in to our - // |preview_contents_| before we've added it to the tab strip. + // If this is being called, something is swapping in to loader's |contents_| + // before we've added it to the tab strip. loader_->ReplacePreviewContents(old_contents, new_contents); } @@ -151,125 +108,53 @@ bool InstantLoader::WebContentsDelegateImpl::ShouldFocusPageAfterCrash() { } void InstantLoader::WebContentsDelegateImpl::LostCapture() { - CommitFromPointerReleaseIfNecessary(); + MaybeCommitFromPointerRelease(); } void InstantLoader::WebContentsDelegateImpl::WebContentsFocused( - content::WebContents* contents) { - loader_->controller_->InstantLoaderContentsFocused(loader_); + content::WebContents* /* contents */) { + loader_->controller_->InstantLoaderContentsFocused(); } bool InstantLoader::WebContentsDelegateImpl::CanDownload( - content::RenderViewHost* render_view_host, - int request_id, - const std::string& request_method) { + content::RenderViewHost* /* render_view_host */, + int /* request_id */, + const std::string& /* request_method */) { // Downloads are disabled. return false; } void InstantLoader::WebContentsDelegateImpl::HandleMouseDown() { - is_pointer_down_from_activate_ = true; + loader_->is_pointer_down_from_activate_ = true; } void InstantLoader::WebContentsDelegateImpl::HandleMouseUp() { - CommitFromPointerReleaseIfNecessary(); + MaybeCommitFromPointerRelease(); } void InstantLoader::WebContentsDelegateImpl::HandlePointerActivate() { - is_pointer_down_from_activate_ = true; + loader_->is_pointer_down_from_activate_ = true; } void InstantLoader::WebContentsDelegateImpl::HandleGestureEnd() { - CommitFromPointerReleaseIfNecessary(); + MaybeCommitFromPointerRelease(); } void InstantLoader::WebContentsDelegateImpl::DragEnded() { // If the user drags, we won't get a mouse up (at least on Linux). Commit the // Instant result when the drag ends, so that during the drag the page won't // move around. - CommitFromPointerReleaseIfNecessary(); + MaybeCommitFromPointerRelease(); } bool InstantLoader::WebContentsDelegateImpl::OnGoToEntryOffset(int offset) { return false; } -void InstantLoader::WebContentsDelegateImpl::DidFinishLoad( - int64 frame_id, - const GURL& validated_url, - bool is_main_frame, - content::RenderViewHost* render_view_host) { - if (is_main_frame && !loader_->supports_instant_) - Send(new ChromeViewMsg_DetermineIfPageSupportsInstant(routing_id())); -} - -bool InstantLoader::WebContentsDelegateImpl::OnMessageReceived( - const IPC::Message& message) { - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(WebContentsDelegateImpl, message) - IPC_MESSAGE_HANDLER(ChromeViewHostMsg_SetSuggestions, OnSetSuggestions) - IPC_MESSAGE_HANDLER(ChromeViewHostMsg_InstantSupportDetermined, - OnInstantSupportDetermined) - IPC_MESSAGE_HANDLER(ChromeViewHostMsg_ShowInstantPreview, - OnShowInstantPreview); - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - return handled; -} - -void InstantLoader::WebContentsDelegateImpl::OnSetSuggestions( - int page_id, - const std::vector<InstantSuggestion>& suggestions) { - DCHECK(loader_->preview_contents()); - DCHECK(loader_->preview_contents_->web_contents()); - content::NavigationEntry* entry = loader_->preview_contents_->web_contents()-> - GetController().GetActiveEntry(); - if (entry && page_id == entry->GetPageID()) { - MaybeSetAndNotifyInstantSupportDetermined(true); - loader_->controller_->SetSuggestions(loader_, suggestions); - } -} - -void InstantLoader::WebContentsDelegateImpl::OnInstantSupportDetermined( - int page_id, - bool result) { - DCHECK(loader_->preview_contents()); - DCHECK(loader_->preview_contents_->web_contents()); - content::NavigationEntry* entry = loader_->preview_contents_->web_contents()-> - GetController().GetActiveEntry(); - if (entry && page_id == entry->GetPageID()) - MaybeSetAndNotifyInstantSupportDetermined(result); -} - -void InstantLoader::WebContentsDelegateImpl::OnShowInstantPreview( - int page_id, - InstantShownReason reason, - int height, - InstantSizeUnits units) { - DCHECK(loader_->preview_contents()); - DCHECK(loader_->preview_contents_->web_contents()); - content::NavigationEntry* entry = loader_->preview_contents_->web_contents()-> - GetController().GetActiveEntry(); - if (entry && page_id == entry->GetPageID()) { - MaybeSetAndNotifyInstantSupportDetermined(true); - loader_->controller_->ShowInstantPreview(loader_, reason, height, units); - } -} - -void InstantLoader::WebContentsDelegateImpl - ::CommitFromPointerReleaseIfNecessary() { - if (is_pointer_down_from_activate_) { - is_pointer_down_from_activate_ = false; - loader_->controller_->CommitInstantLoader(loader_); - } -} - -void InstantLoader::WebContentsDelegateImpl - ::MaybeSetAndNotifyInstantSupportDetermined(bool supports_instant) { - // If we already determined that the loader supports Instant, nothing to do. - if (!loader_->supports_instant_) { - loader_->supports_instant_ = supports_instant; - loader_->controller_->InstantSupportDetermined(loader_, supports_instant); +void InstantLoader::WebContentsDelegateImpl::MaybeCommitFromPointerRelease() { + if (loader_->is_pointer_down_from_activate_) { + loader_->is_pointer_down_from_activate_ = false; + loader_->controller_->CommitIfCurrent(INSTANT_COMMIT_FOCUS_LOST); } } @@ -277,145 +162,118 @@ void InstantLoader::WebContentsDelegateImpl // static InstantLoader* InstantLoader::FromWebContents( - content::WebContents* web_contents) { + const content::WebContents* web_contents) { InstantLoaderUserData* data = static_cast<InstantLoaderUserData*>( web_contents->GetUserData(&kUserDataKey)); return data ? data->loader() : NULL; } InstantLoader::InstantLoader(InstantController* controller, - const std::string& instant_url, - const TabContents* tab_contents) - : controller_(controller), - preview_delegate_(new WebContentsDelegateImpl( - ALLOW_THIS_IN_INITIALIZER_LIST(this))), - preview_contents_( - TabContents::Factory::CreateTabContents( - content::WebContents::CreateWithSessionStorage( - tab_contents->profile(), NULL, MSG_ROUTING_NONE, - tab_contents->web_contents(), - tab_contents->web_contents()->GetController(). - GetSessionStorageNamespaceMap()))), + const std::string& instant_url) + : client_(ALLOW_THIS_IN_INITIALIZER_LIST(this)), + controller_(controller), + delegate_(new WebContentsDelegateImpl( + ALLOW_THIS_IN_INITIALIZER_LIST(this))), + instant_url_(instant_url), supports_instant_(false), - instant_url_(instant_url) { + is_pointer_down_from_activate_(false) { } InstantLoader::~InstantLoader() { } -void InstantLoader::Init() { +void InstantLoader::InitContents(const content::WebContents* active_tab) { + contents_.reset(content::WebContents::CreateWithSessionStorage( + active_tab->GetBrowserContext(), NULL, MSG_ROUTING_NONE, active_tab, + active_tab->GetController().GetSessionStorageNamespaceMap())); + // Not a leak. TabContents will delete itself when the WebContents is gone. + TabContents::Factory::CreateTabContents(contents()); SetupPreviewContents(); - // This HTTP header and value are set on loads that originate from instant. + + // This HTTP header and value are set on loads that originate from Instant. const char kInstantHeader[] = "X-Purpose: Instant"; DVLOG(1) << "LoadURL: " << instant_url_; - preview_contents_->web_contents()->GetController().LoadURL(GURL(instant_url_), - content::Referrer(), content::PAGE_TRANSITION_GENERATED, kInstantHeader); - preview_contents_->web_contents()->WasHidden(); + contents_->GetController().LoadURL(GURL(instant_url_), content::Referrer(), + content::PAGE_TRANSITION_GENERATED, kInstantHeader); + contents_->WasHidden(); } -void InstantLoader::Update(const string16& user_text, bool verbatim) { - // TODO: Support real cursor position. +content::WebContents* InstantLoader::ReleaseContents() { + CleanupPreviewContents(); + return contents_.release(); +} + +void InstantLoader::DidNavigate( + const history::HistoryAddPageArgs& add_page_args) { + last_navigation_ = add_page_args; +} + +void InstantLoader::Update(const string16& text, + size_t selection_start, + size_t selection_end, + bool verbatim) { last_navigation_ = history::HistoryAddPageArgs(); - content::RenderViewHost* rvh = - preview_contents_->web_contents()->GetRenderViewHost(); - rvh->Send(new ChromeViewMsg_SearchBoxChange(rvh->GetRoutingID(), user_text, - verbatim, user_text.size(), user_text.size())); + client_.Update(text, selection_start, selection_end, verbatim); +} + +void InstantLoader::Submit(const string16& text) { + client_.Submit(text); +} + +void InstantLoader::Cancel(const string16& text) { + client_.Cancel(text); } void InstantLoader::SetOmniboxBounds(const gfx::Rect& bounds) { - content::RenderViewHost* rvh = - preview_contents_->web_contents()->GetRenderViewHost(); - rvh->Send(new ChromeViewMsg_SearchBoxResize(rvh->GetRoutingID(), bounds)); + client_.SetOmniboxBounds(bounds); } void InstantLoader::SendAutocompleteResults( const std::vector<InstantAutocompleteResult>& results) { - content::RenderViewHost* rvh = - preview_contents_->web_contents()->GetRenderViewHost(); - rvh->Send(new ChromeViewMsg_SearchBoxAutocompleteResults(rvh->GetRoutingID(), - results)); + client_.SendAutocompleteResults(results); } -void InstantLoader::SendThemeBackgroundInfo( - const ThemeBackgroundInfo& theme_info) { - content::RenderViewHost* rvh = - preview_contents_->web_contents()->GetRenderViewHost(); - rvh->Send(new ChromeViewMsg_SearchBoxThemeChanged(rvh->GetRoutingID(), - theme_info)); -} - -void InstantLoader::SendThemeAreaHeight(int height) { - content::RenderViewHost* rvh = - preview_contents_->web_contents()->GetRenderViewHost(); - rvh->Send(new ChromeViewMsg_SearchBoxThemeAreaHeightChanged( - rvh->GetRoutingID(), height)); +void InstantLoader::UpOrDownKeyPressed(int count) { + client_.UpOrDownKeyPressed(count); } -void InstantLoader::SetDisplayInstantResults(bool display_instant_results) { - content::RenderViewHost* rvh = - preview_contents_->web_contents()->GetRenderViewHost(); - rvh->Send(new ChromeViewMsg_SearchBoxSetDisplayInstantResults( - rvh->GetRoutingID(), display_instant_results)); +void InstantLoader::SearchModeChanged(const chrome::search::Mode& mode) { + client_.SearchModeChanged(mode); } -void InstantLoader::OnUpOrDownKeyPressed(int count) { - content::RenderViewHost* rvh = - preview_contents_->web_contents()->GetRenderViewHost(); - rvh->Send(new ChromeViewMsg_SearchBoxUpOrDownKeyPressed(rvh->GetRoutingID(), - count)); +void InstantLoader::SendThemeBackgroundInfo( + const ThemeBackgroundInfo& theme_info) { + client_.SendThemeBackgroundInfo(theme_info); } -void InstantLoader::SearchModeChanged(const chrome::search::Mode& mode) { - content::RenderViewHost* rvh = - preview_contents_->web_contents()->GetRenderViewHost(); - rvh->Send(new ChromeViewMsg_SearchBoxModeChanged(rvh->GetRoutingID(), mode)); +void InstantLoader::SendThemeAreaHeight(int height) { + client_.SendThemeAreaHeight(height); } -void InstantLoader::DidNavigate( - const history::HistoryAddPageArgs& add_page_args) { - last_navigation_ = add_page_args; +void InstantLoader::SetDisplayInstantResults(bool display_instant_results) { + client_.SetDisplayInstantResults(display_instant_results); } -TabContents* InstantLoader::ReleasePreviewContents(InstantCommitType type, - const string16& text) { - content::RenderViewHost* rvh = - preview_contents_->web_contents()->GetRenderViewHost(); - if (type == INSTANT_COMMIT_FOCUS_LOST) - rvh->Send(new ChromeViewMsg_SearchBoxCancel(rvh->GetRoutingID(), text)); - else - rvh->Send(new ChromeViewMsg_SearchBoxSubmit(rvh->GetRoutingID(), text)); - CleanupPreviewContents(); - return preview_contents_.release(); +void InstantLoader::SetSuggestions( + const std::vector<InstantSuggestion>& suggestions) { + InstantSupportDetermined(true); + controller_->SetSuggestions(contents(), suggestions); } -void InstantLoader::CleanupPreviewContents() { - content::WebContents* old_contents = preview_contents_->web_contents(); - old_contents->RemoveUserData(&kUserDataKey); - old_contents->SetDelegate(NULL); - preview_delegate_->ObserveContents(NULL); - - BlockedContentTabHelper::FromWebContents(old_contents)-> - SetAllContentsBlocked(false); - ConstrainedWindowTabHelper::FromWebContents(old_contents)->set_delegate(NULL); - TabSpecificContentSettings::FromWebContents(old_contents)-> - SetPopupsBlocked(false); - CoreTabHelper::FromWebContents(old_contents)->set_delegate(NULL); - if (ThumbnailTabHelper* thumbnail_tab_helper = - ThumbnailTabHelper::FromWebContents(old_contents)) - thumbnail_tab_helper->set_enabled(true); +void InstantLoader::InstantSupportDetermined(bool supports_instant) { + // If we had already determined that the page supports Instant, nothing to do. + if (supports_instant_) + return; -#if defined(OS_MACOSX) - if (content::RenderWidgetHostView* rwhv = - old_contents->GetRenderWidgetHostView()) - rwhv->SetTakesFocusOnlyOnMouseDown(false); - registrar_.Remove(this, content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED, - content::Source<content::NavigationController>( - &old_contents->GetController())); -#endif + supports_instant_ = supports_instant; + controller_->InstantSupportDetermined(contents(), supports_instant); } -bool InstantLoader::IsPointerDownFromActivate() const { - return preview_delegate_->is_pointer_down_from_activate(); +void InstantLoader::ShowInstantPreview(InstantShownReason reason, + int height, + InstantSizeUnits units) { + InstantSupportDetermined(true); + controller_->ShowInstantPreview(reason, height, units); } void InstantLoader::Observe(int type, @@ -424,7 +282,7 @@ void InstantLoader::Observe(int type, #if defined(OS_MACOSX) if (type == content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED) { if (content::RenderWidgetHostView* rwhv = - preview_contents_->web_contents()->GetRenderWidgetHostView()) + contents_->GetRenderWidgetHostView()) rwhv->SetTakesFocusOnlyOnMouseDown(true); return; } @@ -433,46 +291,79 @@ void InstantLoader::Observe(int type, } void InstantLoader::SetupPreviewContents() { - content::WebContents* new_contents = preview_contents_->web_contents(); - new_contents->SetUserData(&kUserDataKey, new InstantLoaderUserData(this)); - WebContentsDelegateImpl* new_delegate = preview_delegate_.get(); - new_contents->SetDelegate(new_delegate); - new_delegate->ObserveContents(new_contents); + client_.SetContents(contents()); + contents_->SetUserData(&kUserDataKey, new InstantLoaderUserData(this)); + contents_->SetDelegate(delegate_.get()); // Disable popups and such (mainly to avoid losing focus and reverting the // preview prematurely). - BlockedContentTabHelper::FromWebContents(new_contents)-> - SetAllContentsBlocked(true); - ConstrainedWindowTabHelper::FromWebContents(new_contents)-> - set_delegate(new_delegate); - TabSpecificContentSettings::FromWebContents(new_contents)-> - SetPopupsBlocked(true); - CoreTabHelper::FromWebContents(new_contents)->set_delegate(new_delegate); + if (BlockedContentTabHelper* blocked_content_tab_helper = + BlockedContentTabHelper::FromWebContents(contents())) + blocked_content_tab_helper->SetAllContentsBlocked(true); + if (ConstrainedWindowTabHelper* constrained_window_tab_helper = + ConstrainedWindowTabHelper::FromWebContents(contents())) + constrained_window_tab_helper->set_delegate(delegate_.get()); + if (TabSpecificContentSettings* tab_specific_content_settings = + TabSpecificContentSettings::FromWebContents(contents())) + tab_specific_content_settings->SetPopupsBlocked(true); + if (CoreTabHelper* core_tab_helper = + CoreTabHelper::FromWebContents(contents())) + core_tab_helper->set_delegate(delegate_.get()); if (ThumbnailTabHelper* thumbnail_tab_helper = - ThumbnailTabHelper::FromWebContents(new_contents)) + ThumbnailTabHelper::FromWebContents(contents())) thumbnail_tab_helper->set_enabled(false); #if defined(OS_MACOSX) - // If |preview_contents_| does not currently have a RWHV, we will call - // SetTakesFocusOnlyOnMouseDown() as a result of the RENDER_VIEW_HOST_CHANGED - // notification. + // If |contents_| doesn't yet have a RWHV, SetTakesFocusOnlyOnMouseDown() will + // be called later, when NOTIFICATION_RENDER_VIEW_HOST_CHANGED is received. if (content::RenderWidgetHostView* rwhv = - new_contents->GetRenderWidgetHostView()) + contents_->GetRenderWidgetHostView()) rwhv->SetTakesFocusOnlyOnMouseDown(true); registrar_.Add(this, content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED, content::Source<content::NavigationController>( - &new_contents->GetController())); + &contents_->GetController())); +#endif +} + +void InstantLoader::CleanupPreviewContents() { + client_.SetContents(NULL); + contents_->RemoveUserData(&kUserDataKey); + contents_->SetDelegate(NULL); + + if (BlockedContentTabHelper* blocked_content_tab_helper = + BlockedContentTabHelper::FromWebContents(contents())) + blocked_content_tab_helper->SetAllContentsBlocked(false); + if (ConstrainedWindowTabHelper* constrained_window_tab_helper = + ConstrainedWindowTabHelper::FromWebContents(contents())) + constrained_window_tab_helper->set_delegate(NULL); + if (TabSpecificContentSettings* tab_specific_content_settings = + TabSpecificContentSettings::FromWebContents(contents())) + tab_specific_content_settings->SetPopupsBlocked(false); + if (CoreTabHelper* core_tab_helper = + CoreTabHelper::FromWebContents(contents())) + core_tab_helper->set_delegate(NULL); + if (ThumbnailTabHelper* thumbnail_tab_helper = + ThumbnailTabHelper::FromWebContents(contents())) + thumbnail_tab_helper->set_enabled(true); + +#if defined(OS_MACOSX) + if (content::RenderWidgetHostView* rwhv = + contents_->GetRenderWidgetHostView()) + rwhv->SetTakesFocusOnlyOnMouseDown(false); + registrar_.Remove(this, content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED, + content::Source<content::NavigationController>( + &contents_->GetController())); #endif } void InstantLoader::ReplacePreviewContents(content::WebContents* old_contents, content::WebContents* new_contents) { - DCHECK_EQ(old_contents, preview_contents_->web_contents()); + DCHECK_EQ(old_contents, contents()); CleanupPreviewContents(); // We release here without deleting so that the caller still has the - // responsibility for deleting the TabContents. - ignore_result(preview_contents_.release()); - preview_contents_.reset(TabContents::FromWebContents(new_contents)); + // responsibility for deleting the WebContents. + ignore_result(contents_.release()); + contents_.reset(new_contents); SetupPreviewContents(); - controller_->SwappedTabContents(this); + controller_->SwappedWebContents(); } diff --git a/chrome/browser/instant/instant_loader.h b/chrome/browser/instant/instant_loader.h index d995068..c701aa6 100644 --- a/chrome/browser/instant/instant_loader.h +++ b/chrome/browser/instant/instant_loader.h @@ -13,13 +13,12 @@ #include "base/memory/scoped_ptr.h" #include "base/string16.h" #include "chrome/browser/history/history_types.h" -#include "chrome/browser/instant/instant_commit_type.h" +#include "chrome/browser/instant/instant_client.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" struct InstantAutocompleteResult; class InstantController; -class TabContents; struct ThemeBackgroundInfo; namespace chrome { @@ -36,89 +35,46 @@ namespace gfx { class Rect; } -// InstantLoader is created with an "Instant URL". It loads the URL and tells -// the InstantController of all interesting events. For example, it determines -// if the page supports the Instant API (http://dev.chromium.org/searchbox) and -// forwards messages (such as queries and autocomplete suggestions) between the -// page and the controller. -class InstantLoader : public content::NotificationObserver { +// InstantLoader is used to communicate with a preview WebContents that it owns +// and loads the "Instant URL" into. This preview can appear and disappear at +// will as the user types in the omnibox (compare: InstantTab, which talks to a +// committed tab on the tab strip). +class InstantLoader : public InstantClient::Delegate, + public content::NotificationObserver { public: - // Returns the Instant loader for |web_contents| if it's used for Instant. - static InstantLoader* FromWebContents(content::WebContents* web_contents); - - // Creates a new empty WebContents. Use Init() to actually load |instant_url|. - // |tab_contents| is the page the preview will be shown on top of and - // potentially replace. |instant_url| is typically the instant_url field of - // the default search engine's TemplateURL, with the "{searchTerms}" parameter - // replaced with an empty string. - InstantLoader(InstantController* controller, - const std::string& instant_url, - const TabContents* tab_contents); - virtual ~InstantLoader(); - - // Initializes |preview_contents_| and loads |instant_url_|. - void Init(); - - // Tells the preview page that the user typed |user_text| into the omnibox. - // If |verbatim| is false, the page predicts the query the user means to type - // and fetches results for the prediction. If |verbatim| is true, |user_text| - // is taken as the exact query (no prediction is made). - void Update(const string16& user_text, bool verbatim); - - // Tells the preview page of the bounds of the omnibox dropdown (in screen - // coordinates). This is used by the page to offset the results to avoid them - // being covered by the omnibox dropdown. - void SetOmniboxBounds(const gfx::Rect& bounds); - - // Tells the preview page about the available autocomplete results. - void SendAutocompleteResults( - const std::vector<InstantAutocompleteResult>& results); - - // Tells the preview page about the current theme background. - void SendThemeBackgroundInfo(const ThemeBackgroundInfo& theme_info); - - // Tells the preview page about the current theme area height. - void SendThemeAreaHeight(int height); - - // Tells the preview page whether it is allowed to display Instant results. - void SetDisplayInstantResults(bool display_instant_results); + // Returns the Instant loader for |contents| if it's used for Instant. + static InstantLoader* FromWebContents(const content::WebContents* contents); - // Tells the preview page that the user pressed the up or down key. |count| - // is a repeat count, negative for moving up, positive for moving down. - void OnUpOrDownKeyPressed(int count); + // Doesn't take ownership of |controller|. + InstantLoader(InstantController* controller, const std::string& instant_url); + virtual ~InstantLoader(); - // Tells the preview page that the active tab's search mode has changed. - void SearchModeChanged(const chrome::search::Mode& mode); + // The preview WebContents. InstantLoader retains ownership. This will be + // non-NULL after InitFromContents(), and until ReleaseContents() is called. + content::WebContents* contents() const { return contents_.get(); } - // Called by the history tab helper with the information that it would have - // added to the history service had this web contents not been used for - // Instant. - void DidNavigate(const history::HistoryAddPageArgs& add_page_args); + // Creates a new WebContents and loads |instant_url_| into it. |active_tab| is + // the page the preview will be shown on top of and potentially replace. + void InitContents(const content::WebContents* active_tab); - // Releases the preview TabContents passing ownership to the caller. This - // should be called when the preview is committed. Notifies the page but not - // the controller. |text| is the final omnibox text being committed. NOTE: The - // caller should destroy this loader object right after this method, since - // none of the other methods will work once the preview has been released. - TabContents* ReleasePreviewContents(InstantCommitType type, - const string16& text) WARN_UNUSED_RESULT; + // Releases the preview WebContents passing ownership to the caller. This + // should be called when the preview is committed. + content::WebContents* ReleaseContents() WARN_UNUSED_RESULT; - // Severs delegate and observer connections, resets popup blocking, etc., on - // the |preview_contents_|. - void CleanupPreviewContents(); - - // The preview TabContents. The loader retains ownership. This will be - // non-NULL until ReleasePreviewContents() is called. - TabContents* preview_contents() const { return preview_contents_.get(); } + // Returns the URL that we're loading. + const std::string& instant_url() const { return instant_url_; } - // Returns true if the preview page is known to support the Instant API. This + // Returns true if the preview is known to support the Instant API. This // starts out false, and becomes true whenever we get any message from the // page. Once true, it never becomes false (the page isn't expected to drop // Instant API support suddenly). bool supports_instant() const { return supports_instant_; } - // Returns the URL that we're loading. - const std::string& instant_url() const { return instant_url_; } + // Returns true if the mouse or a touch pointer is down due to activating the + // preview contents. + bool is_pointer_down_from_activate() const { + return is_pointer_down_from_activate_; + } // Returns info about the last navigation by the Instant page. If the page // hasn't navigated since the last Update(), the URL is empty. @@ -126,44 +82,63 @@ class InstantLoader : public content::NotificationObserver { return last_navigation_; } - // Returns true if the mouse or a touch pointer is down due to activating the - // preview content. - bool IsPointerDownFromActivate() const; + // Called by the history tab helper with information that it would have added + // to the history service had this WebContents not been used for Instant. + void DidNavigate(const history::HistoryAddPageArgs& add_page_args); + + // Calls through to methods of the same name on InstantClient. + void Update(const string16& text, + size_t selection_start, + size_t selection_end, + bool verbatim); + void Submit(const string16& text); + void Cancel(const string16& text); + void SetOmniboxBounds(const gfx::Rect& bounds); + void SendAutocompleteResults( + const std::vector<InstantAutocompleteResult>& results); + void UpOrDownKeyPressed(int count); + void SearchModeChanged(const chrome::search::Mode& mode); + void SendThemeBackgroundInfo(const ThemeBackgroundInfo& theme_info); + void SendThemeAreaHeight(int height); + void SetDisplayInstantResults(bool display_instant_results); private: class WebContentsDelegateImpl; + // Overridden from InstantClient::Delegate: + virtual void SetSuggestions( + const std::vector<InstantSuggestion>& suggestions) OVERRIDE; + virtual void InstantSupportDetermined(bool supports_instant) OVERRIDE; + virtual void ShowInstantPreview(InstantShownReason reason, + int height, + InstantSizeUnits units) OVERRIDE; + // Overridden from content::NotificationObserver: virtual void Observe(int type, const content::NotificationSource& source, const content::NotificationDetails& details) OVERRIDE; void SetupPreviewContents(); + void CleanupPreviewContents(); void ReplacePreviewContents(content::WebContents* old_contents, content::WebContents* new_contents); + InstantClient client_; InstantController* const controller_; // Delegate of the preview WebContents. Used when the user does some gesture - // on the WebContents and it needs to be activated. This MUST be defined above - // |preview_contents_| so that the delegate can outlive the WebContents. - scoped_ptr<WebContentsDelegateImpl> preview_delegate_; - - // See comments on the getter above. - scoped_ptr<TabContents> preview_contents_; + // on the preview and it needs to be activated. + scoped_ptr<WebContentsDelegateImpl> delegate_; + scoped_ptr<content::WebContents> contents_; - // See comments on the getter above. - bool supports_instant_; - - // See comments on the getter above. const std::string instant_url_; + bool supports_instant_; + bool is_pointer_down_from_activate_; + history::HistoryAddPageArgs last_navigation_; // Used to get notifications about renderers coming and going. content::NotificationRegistrar registrar_; - // See comments on the getter above. - history::HistoryAddPageArgs last_navigation_; - DISALLOW_COPY_AND_ASSIGN(InstantLoader); }; diff --git a/chrome/browser/instant/instant_model.cc b/chrome/browser/instant/instant_model.cc index bafad5a..2a333bd 100644 --- a/chrome/browser/instant/instant_model.cc +++ b/chrome/browser/instant/instant_model.cc @@ -38,7 +38,7 @@ void InstantModel::SetPreviewState(const chrome::search::Mode& mode, PreviewStateChanged(*this)); } -void InstantModel::SetPreviewContents(TabContents* preview_contents) { +void InstantModel::SetPreviewContents(content::WebContents* preview_contents) { if (preview_contents_ == preview_contents) return; @@ -48,7 +48,7 @@ void InstantModel::SetPreviewContents(TabContents* preview_contents) { PreviewStateChanged(*this)); } -TabContents* InstantModel::GetPreviewContents() const { +content::WebContents* InstantModel::GetPreviewContents() const { return controller_->GetPreviewContents(); } diff --git a/chrome/browser/instant/instant_model.h b/chrome/browser/instant/instant_model.h index aacedd2..f125fd5 100644 --- a/chrome/browser/instant/instant_model.h +++ b/chrome/browser/instant/instant_model.h @@ -12,7 +12,10 @@ class InstantController; class InstantModelObserver; -class TabContents; + +namespace content { +class WebContents; +} // Holds state that is important to any views concerned with visibility and // layout of the Instant preview. @@ -31,8 +34,8 @@ class InstantModel { int height, InstantSizeUnits height_units); - void SetPreviewContents(TabContents* preview_contents); - TabContents* GetPreviewContents() const; + void SetPreviewContents(content::WebContents* preview_contents); + content::WebContents* GetPreviewContents() const; // Add and remove observers. void AddObserver(InstantModelObserver* observer) const; @@ -46,7 +49,7 @@ class InstantModel { // Weak. Remembers the last set preview contents to detect changes. Actual // preview contents is fetched from the |controller_| as this may not always // reflect the actual preview in effect. - TabContents* preview_contents_; + content::WebContents* preview_contents_; // Weak. The controller currently holds some model state. // TODO(dhollowa): Remove this, transfer all model state to InstantModel. diff --git a/chrome/browser/instant/instant_tab.cc b/chrome/browser/instant/instant_tab.cc new file mode 100644 index 0000000..c6821728 --- /dev/null +++ b/chrome/browser/instant/instant_tab.cc @@ -0,0 +1,69 @@ +// Copyright 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/instant/instant_tab.h" + +#include "chrome/browser/instant/instant_controller.h" + +InstantTab::InstantTab(InstantController* controller, + content::WebContents* contents) + : client_(ALLOW_THIS_IN_INITIALIZER_LIST(this)), + controller_(controller), + contents_(contents), + supports_instant_(false) { +} + +InstantTab::~InstantTab() { +} + +void InstantTab::Init() { + client_.SetContents(contents_); + client_.DetermineIfPageSupportsInstant(); +} + +void InstantTab::Update(const string16& text, + size_t selection_start, + size_t selection_end, + bool verbatim) { + client_.Update(text, selection_start, selection_end, verbatim); +} + +void InstantTab::Submit(const string16& text) { + client_.Submit(text); +} + +void InstantTab::SendAutocompleteResults( + const std::vector<InstantAutocompleteResult>& results) { + client_.SendAutocompleteResults(results); +} + +void InstantTab::UpOrDownKeyPressed(int count) { + client_.UpOrDownKeyPressed(count); +} + +void InstantTab::SetSuggestions( + const std::vector<InstantSuggestion>& suggestions) { + InstantSupportDetermined(true); + controller_->SetSuggestions(contents_, suggestions); +} + +void InstantTab::InstantSupportDetermined(bool supports_instant) { + // If we had already determined that the page supports Instant, nothing to do. + if (supports_instant_) + return; + + supports_instant_ = supports_instant; + + // If the page doesn't support Instant, stop communicating with it. + if (!supports_instant) + client_.SetContents(NULL); + + controller_->InstantSupportDetermined(contents_, supports_instant); +} + +void InstantTab::ShowInstantPreview(InstantShownReason /* reason */, + int /* height */, + InstantSizeUnits /* units */) { + // The page is a committed tab (i.e., always showing), so nothing to do. +} diff --git a/chrome/browser/instant/instant_tab.h b/chrome/browser/instant/instant_tab.h new file mode 100644 index 0000000..18a51f6 --- /dev/null +++ b/chrome/browser/instant/instant_tab.h @@ -0,0 +1,64 @@ +// Copyright 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_INSTANT_INSTANT_TAB_H_ +#define CHROME_BROWSER_INSTANT_INSTANT_TAB_H_ + +#include <vector> + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "base/string16.h" +#include "chrome/browser/instant/instant_client.h" + +struct InstantAutocompleteResult; +class InstantController; + +namespace content { +class WebContents; +} + +// InstantTab is used to communicate with a committed search results page, i.e., +// an actual tab on the tab strip (compare: InstantLoader, which has a preview +// page that appears and disappears as the user types in the omnibox). +class InstantTab : public InstantClient::Delegate { + public: + // Doesn't take ownership of either |controller| or |contents|. + InstantTab(InstantController* controller, content::WebContents* contents); + virtual ~InstantTab(); + + content::WebContents* contents() const { return contents_; } + + // Start observing |contents_| for messages. Sends a message to determine if + // the page supports the Instant API. + void Init(); + + // Calls through to methods of the same name on InstantClient. + void Update(const string16& text, + size_t selection_start, + size_t selection_end, + bool verbatim); + void Submit(const string16& text); + void SendAutocompleteResults( + const std::vector<InstantAutocompleteResult>& results); + void UpOrDownKeyPressed(int count); + + private: + // Overridden from InstantClient::Delegate: + virtual void SetSuggestions( + const std::vector<InstantSuggestion>& suggestions) OVERRIDE; + virtual void InstantSupportDetermined(bool supports_instant) OVERRIDE; + virtual void ShowInstantPreview(InstantShownReason reason, + int height, + InstantSizeUnits units) OVERRIDE; + + InstantClient client_; + InstantController* const controller_; + content::WebContents* const contents_; + bool supports_instant_; + + DISALLOW_COPY_AND_ASSIGN(InstantTab); +}; + +#endif // CHROME_BROWSER_INSTANT_INSTANT_TAB_H_ diff --git a/chrome/browser/instant/instant_unload_handler.cc b/chrome/browser/instant/instant_unload_handler.cc index 0299057..a93b176 100644 --- a/chrome/browser/instant/instant_unload_handler.cc +++ b/chrome/browser/instant/instant_unload_handler.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -13,25 +13,25 @@ #include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents_delegate.h" -// WebContentsDelegate implementation. This owns the TabContents supplied to the +// WebContentsDelegate implementation. This owns the WebContents supplied to the // constructor. class InstantUnloadHandler::WebContentsDelegateImpl : public content::WebContentsDelegate { public: WebContentsDelegateImpl(InstantUnloadHandler* handler, - TabContents* tab_contents, + content::WebContents* contents, int index) : handler_(handler), - tab_contents_(tab_contents), + contents_(contents), index_(index) { - tab_contents->web_contents()->SetDelegate(this); + contents->SetDelegate(this); } // content::WebContentsDelegate overrides: virtual void WillRunBeforeUnloadConfirm() OVERRIDE { - TabContents* tab = tab_contents_.release(); - tab->web_contents()->SetDelegate(NULL); - handler_->Activate(this, tab, index_); + content::WebContents* contents = contents_.release(); + contents->SetDelegate(NULL); + handler_->Activate(this, contents, index_); } virtual bool ShouldSuppressDialogs() OVERRIDE { @@ -39,16 +39,16 @@ class InstantUnloadHandler::WebContentsDelegateImpl } virtual void CloseContents(content::WebContents* source) OVERRIDE { - tab_contents_->web_contents()->SetDelegate(NULL); + contents_->SetDelegate(NULL); handler_->Destroy(this); } private: InstantUnloadHandler* const handler_; - scoped_ptr<TabContents> tab_contents_; + scoped_ptr<content::WebContents> contents_; - // The index |tab_contents_| was originally at. If we add the tab back we add - // it at this index. + // The index |contents_| was originally at. If we add the tab back we add it + // at this index. const int index_; DISALLOW_COPY_AND_ASSIGN(WebContentsDelegateImpl); @@ -61,24 +61,26 @@ InstantUnloadHandler::InstantUnloadHandler(Browser* browser) InstantUnloadHandler::~InstantUnloadHandler() { } -void InstantUnloadHandler::RunUnloadListenersOrDestroy(TabContents* tab, - int index) { - if (!tab->web_contents()->NeedToFireBeforeUnload()) { +void InstantUnloadHandler::RunUnloadListenersOrDestroy( + content::WebContents* contents, + int index) { + if (!contents->NeedToFireBeforeUnload()) { // Tab doesn't have any beforeunload listeners and can be safely deleted. - delete tab; + delete contents; return; } // Tab has before unload listener. Install a delegate and fire the before // unload listener. - delegates_.push_back(new WebContentsDelegateImpl(this, tab, index)); - tab->web_contents()->GetRenderViewHost()->FirePageBeforeUnload(false); + delegates_.push_back(new WebContentsDelegateImpl(this, contents, index)); + contents->GetRenderViewHost()->FirePageBeforeUnload(false); } void InstantUnloadHandler::Activate(WebContentsDelegateImpl* delegate, - TabContents* tab, + content::WebContents* contents, int index) { - chrome::NavigateParams params(browser_, tab); + chrome::NavigateParams params(browser_, + TabContents::FromWebContents(contents)); params.disposition = NEW_FOREGROUND_TAB; params.tabstrip_index = index; diff --git a/chrome/browser/instant/instant_unload_handler.h b/chrome/browser/instant/instant_unload_handler.h index b505ab8..89562f0 100644 --- a/chrome/browser/instant/instant_unload_handler.h +++ b/chrome/browser/instant/instant_unload_handler.h @@ -1,4 +1,4 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -9,11 +9,14 @@ #include "base/memory/scoped_vector.h" class Browser; -class TabContents; + +namespace content { +class WebContents; +} // InstantUnloadHandler ensures that the beforeunload and unload handlers are // run when using Instant. When the user commits the Instant preview the -// existing TabContents is passed to RunUnloadListenersOrDestroy(). If the tab +// existing WebContents is passed to RunUnloadListenersOrDestroy(). If the tab // has no beforeunload or unload listeners, the tab is deleted; otherwise the // beforeunload and unload listeners are executed. If the beforeunload listener // shows a dialog the tab is added back to the tabstrip at its original location @@ -24,15 +27,17 @@ class InstantUnloadHandler { ~InstantUnloadHandler(); // See class description for details on what this does. - void RunUnloadListenersOrDestroy(TabContents* tab_contents, int index); + void RunUnloadListenersOrDestroy(content::WebContents* contents, int index); private: class WebContentsDelegateImpl; // Invoked if the tab is to be shown, at |index| on the tab strip. This // happens if the before unload listener returns a string. Takes ownership of - // |delegate| and |tab|. - void Activate(WebContentsDelegateImpl* delegate, TabContents* tab, int index); + // |delegate| and |contents|. + void Activate(WebContentsDelegateImpl* delegate, + content::WebContents* contents, + int index); // Destroys the old tab. This is invoked if script tries to close the page. void Destroy(WebContentsDelegateImpl* delegate); diff --git a/chrome/browser/task_manager/task_manager_resource_providers.cc b/chrome/browser/task_manager/task_manager_resource_providers.cc index 37add95..b948594 100644 --- a/chrome/browser/task_manager/task_manager_resource_providers.cc +++ b/chrome/browser/task_manager/task_manager_resource_providers.cc @@ -285,7 +285,7 @@ TaskManagerTabContentsResource::TaskManagerTabContentsResource( i != BrowserList::end(); ++i) { if ((*i)->instant_controller() && (*i)->instant_controller()->instant()->GetPreviewContents() == - tab_contents_) { + tab_contents_->web_contents()) { is_instant_preview_ = true; break; } diff --git a/chrome/browser/ui/browser_instant_controller.cc b/chrome/browser/ui/browser_instant_controller.cc index 3cab847..b9ae096 100644 --- a/chrome/browser/ui/browser_instant_controller.cc +++ b/chrome/browser/ui/browser_instant_controller.cc @@ -4,18 +4,15 @@ #include "chrome/browser/ui/browser_instant_controller.h" -#include "chrome/browser/browser_shutdown.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/prefs/pref_service.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/themes/theme_service.h" #include "chrome/browser/themes/theme_service_factory.h" #include "chrome/browser/ui/browser.h" -#include "chrome/browser/ui/browser_tabstrip.h" #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/omnibox/location_bar.h" #include "chrome/browser/ui/search/search.h" -#include "chrome/browser/ui/search/search_model.h" #include "chrome/browser/ui/search/search_tab_helper.h" #include "chrome/browser/ui/tab_contents/tab_contents.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" @@ -23,7 +20,6 @@ #include "chrome/common/chrome_notification_types.h" #include "chrome/common/pref_names.h" #include "content/public/browser/notification_service.h" -#include "content/public/browser/web_contents.h" #include "grit/theme_resources.h" #include "ui/gfx/color_utils.h" #include "ui/gfx/sys_color_change_listener.h" @@ -88,23 +84,24 @@ bool BrowserInstantController::OpenInstant(WindowOpenDisposition disposition) { INSTANT_COMMIT_PRESSED_ENTER : INSTANT_COMMIT_PRESSED_ALT_ENTER); } -void BrowserInstantController::CommitInstant(TabContents* preview, +void BrowserInstantController::CommitInstant(content::WebContents* preview, bool in_new_tab) { if (in_new_tab) { // TabStripModel takes ownership of |preview|. - browser_->tab_strip_model()->AddWebContents(preview->web_contents(), -1, + browser_->tab_strip_model()->AddWebContents(preview, -1, instant_.last_transition_type(), TabStripModel::ADD_ACTIVE); } else { - TabContents* active_tab = - browser_->tab_strip_model()->GetActiveTabContents(); - int index = browser_->tab_strip_model()->GetIndexOfTabContents(active_tab); + content::WebContents* active_tab = + browser_->tab_strip_model()->GetActiveWebContents(); + int index = browser_->tab_strip_model()->GetIndexOfWebContents(active_tab); DCHECK_NE(TabStripModel::kNoTab, index); // TabStripModel takes ownership of |preview|. - browser_->tab_strip_model()->ReplaceTabContentsAt(index, preview); + browser_->tab_strip_model()->ReplaceTabContentsAt(index, + TabContents::FromWebContents(preview)); // InstantUnloadHandler takes ownership of |active_tab|. instant_unload_handler_.RunUnloadListenersOrDestroy(active_tab, index); - GURL url = preview->web_contents()->GetURL(); + GURL url = preview->GetURL(); DCHECK(browser_->profile()->GetExtensionService()); if (browser_->profile()->GetExtensionService()->IsInstalledApp(url)) { AppLauncherHandler::RecordAppLaunchType( @@ -125,12 +122,11 @@ gfx::Rect BrowserInstantController::GetInstantBounds() { void BrowserInstantController::InstantPreviewFocused() { // NOTE: This is only invoked on aura. - browser_->window()->WebContentsFocused( - instant_.GetPreviewContents()->web_contents()); + browser_->window()->WebContentsFocused(instant_.GetPreviewContents()); } -TabContents* BrowserInstantController::GetActiveTabContents() const { - return browser_->tab_strip_model()->GetActiveTabContents(); +content::WebContents* BrowserInstantController::GetActiveWebContents() const { + return browser_->tab_strip_model()->GetActiveWebContents(); } void BrowserInstantController::ActiveTabChanged() { diff --git a/chrome/browser/ui/browser_instant_controller.h b/chrome/browser/ui/browser_instant_controller.h index ef23d3a..44d21e7 100644 --- a/chrome/browser/ui/browser_instant_controller.h +++ b/chrome/browser/ui/browser_instant_controller.h @@ -19,9 +19,12 @@ class Browser; struct InstantSuggestion; class PrefService; class Profile; -class TabContents; class ThemeService; +namespace content { +class WebContents; +} + namespace gfx { class Rect; } @@ -50,7 +53,7 @@ class BrowserInstantController : public content::NotificationObserver, // Invoked by |instant_| to commit the |preview| by merging it into the active // tab or adding it as a new tab. We take ownership of |preview|. - void CommitInstant(TabContents* preview, bool in_new_tab); + void CommitInstant(content::WebContents* preview, bool in_new_tab); // Invoked by |instant_| to autocomplete the |suggestion| into the omnibox. void SetInstantSuggestion(const InstantSuggestion& suggestion); @@ -65,7 +68,7 @@ class BrowserInstantController : public content::NotificationObserver, // Invoked by |instant_| to get the currently active tab, over which the // preview would be shown. - TabContents* GetActiveTabContents() const; + content::WebContents* GetActiveWebContents() const; // Invoked by |browser_| when the active tab changes. void ActiveTabChanged(); diff --git a/chrome/browser/ui/cocoa/tab_contents/instant_preview_controller_mac.mm b/chrome/browser/ui/cocoa/tab_contents/instant_preview_controller_mac.mm index eb8d1b3..d915d63 100644 --- a/chrome/browser/ui/cocoa/tab_contents/instant_preview_controller_mac.mm +++ b/chrome/browser/ui/cocoa/tab_contents/instant_preview_controller_mac.mm @@ -7,7 +7,6 @@ #include "chrome/browser/instant/instant_model.h" #import "chrome/browser/ui/cocoa/browser_window_controller.h" #import "chrome/browser/ui/cocoa/tab_contents/previewable_contents_controller.h" -#include "chrome/browser/ui/tab_contents/tab_contents.h" InstantPreviewControllerMac::InstantPreviewControllerMac( Browser* browser, @@ -25,7 +24,7 @@ void InstantPreviewControllerMac::PreviewStateChanged( const InstantModel& model) { if (model.mode().is_search_suggestions()) { // TODO(dhollowa): Needs height and units implementation on Mac. - [preview_ showPreview:model.GetPreviewContents()->web_contents()]; + [preview_ showPreview:model.GetPreviewContents()]; } else { [preview_ hidePreview]; } diff --git a/chrome/browser/ui/gtk/browser_window_gtk.cc b/chrome/browser/ui/gtk/browser_window_gtk.cc index d74e7e9..04dba7d 100644 --- a/chrome/browser/ui/gtk/browser_window_gtk.cc +++ b/chrome/browser/ui/gtk/browser_window_gtk.cc @@ -1216,7 +1216,7 @@ void BrowserWindowGtk::ActiveTabChanged(WebContents* old_contents, InfoBarTabHelper* new_infobar_tab_helper = InfoBarTabHelper::FromWebContents(new_contents); infobar_container_->ChangeTabContents(new_infobar_tab_helper); - contents_container_->SetTab(TabContents::FromWebContents(new_contents)); + contents_container_->SetTab(new_contents); // TODO(estade): after we manage browser activation, add a check to make sure // we are the active browser before calling RestoreFocus(). @@ -1282,10 +1282,10 @@ bool BrowserWindowGtk::DrawInfoBarArrows(int* x) const { extensions::ActiveTabPermissionGranter* BrowserWindowGtk::GetActiveTabPermissionGranter() { - TabContents* tab = GetDisplayedTab(); + WebContents* tab = GetDisplayedTab(); if (!tab) return NULL; - return extensions::TabHelper::FromWebContents(tab->web_contents())-> + return extensions::TabHelper::FromWebContents(tab)-> active_tab_permission_granter(); } @@ -1305,10 +1305,9 @@ gboolean BrowserWindowGtk::OnConfigure(GtkWidget* widget, GetLocationBar()->GetLocationEntry()->CloseOmniboxPopup(); - TabContents* tab = GetDisplayedTab(); - if (tab) { - tab->web_contents()->GetRenderViewHost()->NotifyMoveOrResizeStarted(); - } + WebContents* tab = GetDisplayedTab(); + if (tab) + tab->GetRenderViewHost()->NotifyMoveOrResizeStarted(); if (bounds_.size() != bounds.size()) UpdateWindowShape(bounds.width(), bounds.height()); @@ -1510,7 +1509,7 @@ void BrowserWindowGtk::RegisterUserPrefs(PrefService* prefs) { PrefService::SYNCABLE_PREF); } -TabContents* BrowserWindowGtk::GetDisplayedTab() { +WebContents* BrowserWindowGtk::GetDisplayedTab() { return contents_container_->GetVisibleTab(); } @@ -1918,9 +1917,7 @@ void BrowserWindowGtk::MaybeShowBookmarkBar(bool animate) { if (!IsBookmarkBarSupported()) return; - TabContents* tab = GetDisplayedTab(); - - if (tab) + if (GetDisplayedTab()) bookmark_bar_->SetPageNavigator(browser_.get()); BookmarkBar::State state = browser_->bookmark_bar_state(); @@ -2309,8 +2306,8 @@ void BrowserWindowGtk::UpdateDevToolsForContents(WebContents* contents) { devtools_container_->DetachTab( devtools_window_->tab_contents()->web_contents()); } - devtools_container_->SetTab( - new_devtools_window ? new_devtools_window->tab_contents() : NULL); + devtools_container_->SetTab(new_devtools_window ? + new_devtools_window->tab_contents()->web_contents() : NULL); if (new_devtools_window) { // WebContentsViewGtk::WasShown is not called when tab contents is shown // by anything other than user selecting a Tab. diff --git a/chrome/browser/ui/gtk/browser_window_gtk.h b/chrome/browser/ui/gtk/browser_window_gtk.h index 4361fbb..27551ec 100644 --- a/chrome/browser/ui/gtk/browser_window_gtk.h +++ b/chrome/browser/ui/gtk/browser_window_gtk.h @@ -1,4 +1,4 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -248,7 +248,7 @@ class BrowserWindowGtk gfx::Rect bounds() const { return bounds_; } // Returns the tab we're currently displaying in the tab contents container. - TabContents* GetDisplayedTab(); + content::WebContents* GetDisplayedTab(); static void RegisterUserPrefs(PrefService* prefs); diff --git a/chrome/browser/ui/gtk/constrained_web_dialog_delegate_gtk.cc b/chrome/browser/ui/gtk/constrained_web_dialog_delegate_gtk.cc index b249d75..05dfb0f 100644 --- a/chrome/browser/ui/gtk/constrained_web_dialog_delegate_gtk.cc +++ b/chrome/browser/ui/gtk/constrained_web_dialog_delegate_gtk.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. diff --git a/chrome/browser/ui/gtk/tab_contents_container_gtk.cc b/chrome/browser/ui/gtk/tab_contents_container_gtk.cc index 4de25a9..3dacd5e 100644 --- a/chrome/browser/ui/gtk/tab_contents_container_gtk.cc +++ b/chrome/browser/ui/gtk/tab_contents_container_gtk.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -8,7 +8,6 @@ #include "base/i18n/rtl.h" #include "chrome/browser/ui/gtk/status_bubble_gtk.h" -#include "chrome/browser/ui/tab_contents/tab_contents.h" #include "chrome/common/chrome_notification_types.h" #include "content/public/browser/notification_source.h" #include "content/public/browser/render_widget_host_view.h" @@ -17,8 +16,6 @@ #include "ui/base/gtk/gtk_floating_container.h" #include "ui/gfx/native_widget_types.h" -using content::WebContents; - TabContentsContainerGtk::TabContentsContainerGtk(StatusBubbleGtk* status_bubble) : tab_(NULL), preview_(NULL), @@ -64,7 +61,7 @@ void TabContentsContainerGtk::Init() { ViewIDUtil::SetDelegateForWidget(widget(), this); } -void TabContentsContainerGtk::SetTab(TabContents* tab) { +void TabContentsContainerGtk::SetTab(content::WebContents* tab) { if (tab_ == tab) return; @@ -83,7 +80,7 @@ void TabContentsContainerGtk::SetTab(TabContents* tab) { // Make sure that the tab is below the find bar. Sometimes the content // native view will be null. - GtkWidget* widget = tab_->web_contents()->GetContentNativeView(); + GtkWidget* widget = tab_->GetContentNativeView(); if (widget) { GdkWindow* content_gdk_window = gtk_widget_get_window(widget); if (content_gdk_window) @@ -92,13 +89,13 @@ void TabContentsContainerGtk::SetTab(TabContents* tab) { } } -void TabContentsContainerGtk::SetPreview(TabContents* preview) { +void TabContentsContainerGtk::SetPreview(content::WebContents* preview) { if (preview_ == preview) return; if (preview_) { HideTab(preview_); - GtkWidget* preview_widget = preview_->web_contents()->GetNativeView(); + GtkWidget* preview_widget = preview_->GetNativeView(); if (preview_widget) gtk_container_remove(GTK_CONTAINER(expanded_), preview_widget); } @@ -109,30 +106,30 @@ void TabContentsContainerGtk::SetPreview(TabContents* preview) { PackTab(preview_); } -void TabContentsContainerGtk::PackTab(TabContents* tab) { - gfx::NativeView widget = tab->web_contents()->GetNativeView(); +void TabContentsContainerGtk::PackTab(content::WebContents* tab) { + gfx::NativeView widget = tab->GetNativeView(); if (widget) { if (gtk_widget_get_parent(widget) != expanded_) gtk_container_add(GTK_CONTAINER(expanded_), widget); gtk_widget_show(widget); } - tab->web_contents()->WasShown(); + tab->WasShown(); registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, - content::Source<WebContents>(tab->web_contents())); + content::Source<content::WebContents>(tab)); } -void TabContentsContainerGtk::HideTab(TabContents* tab) { - gfx::NativeView widget = tab->web_contents()->GetNativeView(); +void TabContentsContainerGtk::HideTab(content::WebContents* tab) { + gfx::NativeView widget = tab->GetNativeView(); if (widget) gtk_widget_hide(widget); - tab->web_contents()->WasHidden(); + tab->WasHidden(); registrar_.Remove(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, - content::Source<WebContents>(tab->web_contents())); + content::Source<content::WebContents>(tab)); } -void TabContentsContainerGtk::DetachTab(WebContents* tab) { +void TabContentsContainerGtk::DetachTab(content::WebContents* tab) { gfx::NativeView widget = tab->GetNativeView(); // It is possible to detach an unrealized, unparented WebContents if you @@ -151,15 +148,16 @@ void TabContentsContainerGtk::Observe( const content::NotificationSource& source, const content::NotificationDetails& details) { DCHECK_EQ(content::NOTIFICATION_WEB_CONTENTS_DESTROYED, type); - WebContentsDestroyed(content::Source<WebContents>(source).ptr()); + WebContentsDestroyed(content::Source<content::WebContents>(source).ptr()); } -void TabContentsContainerGtk::WebContentsDestroyed(WebContents* contents) { +void TabContentsContainerGtk::WebContentsDestroyed( + content::WebContents* contents) { // Sometimes, a WebContents is destroyed before we know about it. This allows // us to clean up our state in case this happens. - if (preview_ && contents == preview_->web_contents()) + if (contents == preview_) SetPreview(NULL); - else if (tab_ && contents == tab_->web_contents()) + else if (contents == tab_) SetTab(NULL); else NOTREACHED(); @@ -171,7 +169,7 @@ void TabContentsContainerGtk::WebContentsDestroyed(WebContents* contents) { gboolean TabContentsContainerGtk::OnFocus(GtkWidget* widget, GtkDirectionType focus) { if (preview_) { - gtk_widget_child_focus(tab_->web_contents()->GetContentNativeView(), focus); + gtk_widget_child_focus(tab_->GetContentNativeView(), focus); return TRUE; } diff --git a/chrome/browser/ui/gtk/tab_contents_container_gtk.h b/chrome/browser/ui/gtk/tab_contents_container_gtk.h index 6ba8f2d2..9b8cd79 100644 --- a/chrome/browser/ui/gtk/tab_contents_container_gtk.h +++ b/chrome/browser/ui/gtk/tab_contents_container_gtk.h @@ -1,4 +1,4 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -16,7 +16,6 @@ #include "ui/base/gtk/owned_widget_gtk.h" class StatusBubbleGtk; -class TabContents; namespace content { class WebContents; @@ -33,14 +32,16 @@ class TabContentsContainerGtk : public content::NotificationObserver, void Init(); // Make the specified tab visible. - void SetTab(TabContents* tab); - TabContents* tab() const { return tab_; } + void SetTab(content::WebContents* tab); + content::WebContents* tab() const { return tab_; } - void SetPreview(TabContents* preview); + void SetPreview(content::WebContents* preview); bool HasPreview() const { return preview_ != NULL; } - // Returns the TabContents currently displayed. - TabContents* GetVisibleTab() const { return preview_ ? preview_ : tab_; } + // Returns the WebContents currently displayed. + content::WebContents* GetVisibleTab() const { + return preview_ ? preview_ : tab_; + } // Remove the tab from the hierarchy. void DetachTab(content::WebContents* tab); @@ -68,10 +69,10 @@ class TabContentsContainerGtk : public content::NotificationObserver, TabContentsContainerGtk* tab_contents_container); // Adds |tab| to the container and starts showing it. - void PackTab(TabContents* tab); + void PackTab(content::WebContents* tab); // Stops showing |tab|. - void HideTab(TabContents* tab); + void HideTab(content::WebContents* tab); // Handle focus traversal on the tab contents container. Focus should not // traverse to the preview contents. @@ -80,13 +81,13 @@ class TabContentsContainerGtk : public content::NotificationObserver, content::NotificationRegistrar registrar_; - // The TabContents for the currently selected tab. This will be showing + // The WebContents for the currently selected tab. This will be showing // unless there is a preview contents. - TabContents* tab_; + content::WebContents* tab_; // The current preview contents (for instant). If non-NULL, it will be // visible. - TabContents* preview_; + content::WebContents* preview_; // The status bubble manager. Always non-NULL. StatusBubbleGtk* status_bubble_; diff --git a/chrome/browser/ui/omnibox/omnibox_edit_model.cc b/chrome/browser/ui/omnibox/omnibox_edit_model.cc index 02eb0f1..5a89651 100644 --- a/chrome/browser/ui/omnibox/omnibox_edit_model.cc +++ b/chrome/browser/ui/omnibox/omnibox_edit_model.cc @@ -313,20 +313,16 @@ bool OmniboxEditModel::UseVerbatimInstant() { return true; #endif - // The value of input.prevent_inline_autocomplete() is determined by + // The value of input.prevent_inline_autocomplete() is determined by the // following conditions: - // 1. If the caret is at the end of the text (checked below). + // 1. If the caret is at the end of the text. // 2. If it's in IME composition mode. - // As we use a separated widget for displaying the Instant suggest, it won't - // interfere with IME composition, so we don't need to care about the value of + // We send the caret position to Instant (so it can determine #1 itself), and + // we use a separated widget for displaying the Instant suggest (so it doesn't + // interfere with #2). So, we don't need to care about the value of // input.prevent_inline_autocomplete() here. - if (view_->DeleteAtEndPressed() || (popup_->selected_line() != 0) || - just_deleted_text_ || !inline_autocomplete_text_.empty()) - return true; - - size_t start, end; - view_->GetSelectionBounds(&start, &end); - return (start != end) || (start != view_->GetText().length()); + return view_->DeleteAtEndPressed() || popup_->selected_line() != 0 || + just_deleted_text_; } string16 OmniboxEditModel::GetDesiredTLD() const { @@ -1189,17 +1185,9 @@ bool OmniboxEditModel::DoInstant(const AutocompleteMatch& match) { // The two pieces of text we want to send Instant, viz., what the user has // typed, and the full omnibox text including any inline autocompletion. - string16 user_text = user_text_; - string16 full_text = user_text_ + inline_autocomplete_text_; - - // If there's temporary text, that overrides the user_text. In this case, we - // should ignore any inline_autocomplete_text_, because it won't be visible. - if (has_temporary_text_) - user_text = full_text = CurrentMatch().fill_into_edit; - - // Remove keyword if we're in keyword mode. - user_text = DisplayTextFromUserText(user_text); - full_text = DisplayTextFromUserText(full_text); + string16 user_text = has_temporary_text_ ? + match.fill_into_edit : DisplayTextFromUserText(user_text_); + string16 full_text = view_->GetText(); // Remove "?" if we're in forced query mode. AutocompleteInput::RemoveForcedQueryStringIfNecessary( @@ -1207,8 +1195,11 @@ bool OmniboxEditModel::DoInstant(const AutocompleteMatch& match) { AutocompleteInput::RemoveForcedQueryStringIfNecessary( autocomplete_controller_->input().type(), &full_text); - return instant->Update(match, user_text, full_text, UseVerbatimInstant(), - user_input_in_progress_, popup_->IsOpen()); + size_t start, end; + view_->GetSelectionBounds(&start, &end); + + return instant->Update(match, user_text, full_text, start, end, + UseVerbatimInstant(), user_input_in_progress_, popup_->IsOpen()); } void OmniboxEditModel::DoPrerender(const AutocompleteMatch& match) { diff --git a/chrome/browser/ui/search/search_tab_helper.cc b/chrome/browser/ui/search/search_tab_helper.cc index d74e9ef..6b46fd7 100644 --- a/chrome/browser/ui/search/search_tab_helper.cc +++ b/chrome/browser/ui/search/search_tab_helper.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -39,6 +39,7 @@ SearchTabHelper::SearchTabHelper(content::WebContents* web_contents) : WebContentsObserver(web_contents), is_search_enabled_(IsSearchEnabled(web_contents)), is_initial_navigation_commit_(true), + user_input_in_progress_(false), model_(web_contents) { if (!is_search_enabled_) return; @@ -58,13 +59,11 @@ void SearchTabHelper::OmniboxEditModelChanged(bool user_input_in_progress, if (!is_search_enabled_) return; - if (user_input_in_progress) { - const Mode new_mode = Mode(Mode::MODE_SEARCH_SUGGESTIONS, - model_.mode().origin, true); - model_.SetMode(new_mode); - } else if (cancelling) { - UpdateModelBasedOnURL(web_contents()->GetURL(), true); - } + user_input_in_progress_ = user_input_in_progress; + if (!user_input_in_progress && !cancelling) + return; + + UpdateModelBasedOnURL(web_contents()->GetURL(), true); } void SearchTabHelper::NavigationEntryUpdated() { @@ -112,6 +111,8 @@ void SearchTabHelper::UpdateModelBasedOnURL(const GURL& url, bool animate) { type = Mode::MODE_SEARCH_RESULTS; origin = Mode::ORIGIN_SEARCH; } + if (user_input_in_progress_) + type = Mode::MODE_SEARCH_SUGGESTIONS; model_.SetMode(Mode(type, origin, animate)); } diff --git a/chrome/browser/ui/search/search_tab_helper.h b/chrome/browser/ui/search/search_tab_helper.h index 5a40934d..89f02ba 100644 --- a/chrome/browser/ui/search/search_tab_helper.h +++ b/chrome/browser/ui/search/search_tab_helper.h @@ -1,4 +1,4 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -68,6 +68,9 @@ class SearchTabHelper : public content::WebContentsObserver, bool is_initial_navigation_commit_; + // Tracks the last value passed to OmniboxEditModelChanged(). + bool user_input_in_progress_; + // Model object for UI that cares about search state. SearchModel model_; diff --git a/chrome/browser/ui/views/frame/instant_preview_controller_views.cc b/chrome/browser/ui/views/frame/instant_preview_controller_views.cc index 6fcf1ae..8c66404 100644 --- a/chrome/browser/ui/views/frame/instant_preview_controller_views.cc +++ b/chrome/browser/ui/views/frame/instant_preview_controller_views.cc @@ -7,7 +7,6 @@ #include "chrome/browser/instant/instant_model.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" -#include "chrome/browser/ui/tab_contents/tab_contents.h" #include "chrome/browser/ui/view_ids.h" #include "chrome/browser/ui/views/frame/contents_container.h" #include "ui/views/controls/webview/webview.h" @@ -30,8 +29,7 @@ void InstantPreviewControllerViews::PreviewStateChanged( preview_.reset(new views::WebView(browser_->profile())); preview_->set_id(VIEW_ID_TAB_CONTAINER); } - content::WebContents* web_contents = - model.GetPreviewContents()->web_contents(); + content::WebContents* web_contents = model.GetPreviewContents(); contents_->SetPreview(preview_.get(), web_contents, model.height(), model.height_units()); preview_->SetWebContents(web_contents); diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 1e1b098..23201d1 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -1,5 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. @@ -917,6 +916,8 @@ 'browser/infobars/infobar_tab_helper.h', 'browser/infobars/insecure_content_infobar_delegate.cc', 'browser/infobars/insecure_content_infobar_delegate.h', + 'browser/instant/instant_client.cc', + 'browser/instant/instant_client.h', 'browser/instant/instant_commit_type.h', 'browser/instant/instant_controller.cc', 'browser/instant/instant_controller.h', @@ -927,6 +928,8 @@ 'browser/instant/instant_model_observer.h', 'browser/instant/instant_preview_controller.cc', 'browser/instant/instant_preview_controller.h', + 'browser/instant/instant_tab.cc', + 'browser/instant/instant_tab.h', 'browser/instant/instant_unload_handler.cc', 'browser/instant/instant_unload_handler.h', 'browser/intents/cws_intents_registry.cc', diff --git a/chrome/common/instant_types.cc b/chrome/common/instant_types.cc index de93581..1f2c0e2 100644 --- a/chrome/common/instant_types.cc +++ b/chrome/common/instant_types.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. diff --git a/chrome/common/instant_types.h b/chrome/common/instant_types.h index ddb4052..90a77ac 100644 --- a/chrome/common/instant_types.h +++ b/chrome/common/instant_types.h @@ -1,4 +1,4 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. diff --git a/chrome/renderer/resources/extensions/searchbox_api.js b/chrome/renderer/resources/extensions/searchbox_api.js index 2c6abc4..7952b3b 100644 --- a/chrome/renderer/resources/extensions/searchbox_api.js +++ b/chrome/renderer/resources/extensions/searchbox_api.js @@ -1,4 +1,4 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. diff --git a/chrome/renderer/searchbox/searchbox.cc b/chrome/renderer/searchbox/searchbox.cc index 9e30ca2..2a3d2c4 100644 --- a/chrome/renderer/searchbox/searchbox.cc +++ b/chrome/renderer/searchbox/searchbox.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -122,6 +122,7 @@ void SearchBox::OnChange(const string16& query, selection_start_ = selection_start; selection_end_ = selection_end; if (render_view()->GetWebView() && render_view()->GetWebView()->mainFrame()) { + DVLOG(1) << render_view() << " OnChange"; extensions_v8::SearchBoxExtension::DispatchChange( render_view()->GetWebView()->mainFrame()); } @@ -132,6 +133,7 @@ void SearchBox::OnSubmit(const string16& query) { verbatim_ = true; selection_start_ = selection_end_ = query_.size(); if (render_view()->GetWebView() && render_view()->GetWebView()->mainFrame()) { + DVLOG(1) << render_view() << " OnSubmit"; extensions_v8::SearchBoxExtension::DispatchSubmit( render_view()->GetWebView()->mainFrame()); } @@ -143,6 +145,7 @@ void SearchBox::OnCancel(const string16& query) { verbatim_ = true; selection_start_ = selection_end_ = query_.size(); if (render_view()->GetWebView() && render_view()->GetWebView()->mainFrame()) { + DVLOG(1) << render_view() << " OnCancel"; extensions_v8::SearchBoxExtension::DispatchCancel( render_view()->GetWebView()->mainFrame()); } @@ -152,6 +155,7 @@ void SearchBox::OnCancel(const string16& query) { void SearchBox::OnResize(const gfx::Rect& bounds) { rect_ = bounds; if (render_view()->GetWebView() && render_view()->GetWebView()->mainFrame()) { + DVLOG(1) << render_view() << " OnResize"; extensions_v8::SearchBoxExtension::DispatchResize( render_view()->GetWebView()->mainFrame()); } @@ -161,6 +165,7 @@ void SearchBox::OnDetermineIfPageSupportsInstant() { if (render_view()->GetWebView() && render_view()->GetWebView()->mainFrame()) { bool result = extensions_v8::SearchBoxExtension::PageSupportsInstant( render_view()->GetWebView()->mainFrame()); + DVLOG(1) << render_view() << " PageSupportsInstant: " << result; render_view()->Send(new ChromeViewHostMsg_InstantSupportDetermined( render_view()->GetRoutingID(), render_view()->GetPageId(), result)); } @@ -171,6 +176,7 @@ void SearchBox::OnAutocompleteResults( results_base_ += autocomplete_results_.size(); autocomplete_results_ = results; if (render_view()->GetWebView() && render_view()->GetWebView()->mainFrame()) { + DVLOG(1) << render_view() << " OnAutocompleteResults"; extensions_v8::SearchBoxExtension::DispatchAutocompleteResults( render_view()->GetWebView()->mainFrame()); } @@ -178,6 +184,7 @@ void SearchBox::OnAutocompleteResults( void SearchBox::OnUpOrDownKeyPressed(int count) { if (render_view()->GetWebView() && render_view()->GetWebView()->mainFrame()) { + DVLOG(1) << render_view() << " OnKeyPress: " << count; extensions_v8::SearchBoxExtension::DispatchUpOrDownKeyPress( render_view()->GetWebView()->mainFrame(), count); } @@ -186,6 +193,7 @@ void SearchBox::OnUpOrDownKeyPressed(int count) { void SearchBox::OnModeChanged(const chrome::search::Mode& mode) { mode_ = mode; if (render_view()->GetWebView() && render_view()->GetWebView()->mainFrame()) { + DVLOG(1) << render_view() << " OnModeChanged"; extensions_v8::SearchBoxExtension::DispatchContextChange( render_view()->GetWebView()->mainFrame()); } diff --git a/chrome/renderer/searchbox/searchbox_extension.cc b/chrome/renderer/searchbox/searchbox_extension.cc index 0cb3907..bf2cb9e 100644 --- a/chrome/renderer/searchbox/searchbox_extension.cc +++ b/chrome/renderer/searchbox/searchbox_extension.cc @@ -319,7 +319,8 @@ v8::Handle<v8::Value> SearchBoxExtensionWrapper::GetQuery( content::RenderView* render_view = GetRenderView(); if (!render_view) return v8::Undefined(); - DVLOG(1) << "GetQuery: '" << SearchBox::Get(render_view)->query() << "'"; + DVLOG(1) << render_view << " GetQuery: '" + << SearchBox::Get(render_view)->query() << "'"; return UTF16ToV8String(SearchBox::Get(render_view)->query()); } @@ -329,7 +330,8 @@ v8::Handle<v8::Value> SearchBoxExtensionWrapper::GetVerbatim( content::RenderView* render_view = GetRenderView(); if (!render_view) return v8::Undefined(); - DVLOG(1) << "GetVerbatim: " << SearchBox::Get(render_view)->verbatim(); + DVLOG(1) << render_view << " GetVerbatim: " + << SearchBox::Get(render_view)->verbatim(); return v8::Boolean::New(SearchBox::Get(render_view)->verbatim()); } @@ -390,13 +392,13 @@ v8::Handle<v8::Value> SearchBoxExtensionWrapper::GetHeight( // static v8::Handle<v8::Value> SearchBoxExtensionWrapper::GetAutocompleteResults( const v8::Arguments& args) { - DVLOG(1) << "GetAutocompleteResults"; content::RenderView* render_view = GetRenderView(); if (!render_view) return v8::Undefined(); + DVLOG(1) << render_view << " GetAutocompleteResults"; const std::vector<InstantAutocompleteResult>& results = SearchBox::Get(render_view)->GetAutocompleteResults(); - const size_t results_base = SearchBox::Get(render_view)->results_base(); + size_t results_base = SearchBox::Get(render_view)->results_base(); v8::Handle<v8::Array> results_array = v8::Array::New(results.size()); for (size_t i = 0; i < results.size(); ++i) { @@ -427,7 +429,7 @@ v8::Handle<v8::Value> SearchBoxExtensionWrapper::GetContext( if (!render_view) return v8::Undefined(); const chrome::search::Mode& mode = SearchBox::Get(render_view)->mode(); - DVLOG(1) << "GetContext: " << mode.origin << ":" << mode.mode; + DVLOG(1) << render_view << " GetContext: " << mode.origin << ":" << mode.mode; v8::Handle<v8::Object> context = v8::Object::New(); context->Set(v8::String::New("isNewTabPage"), v8::Boolean::New(mode.is_ntp())); @@ -449,10 +451,10 @@ v8::Handle<v8::Value> SearchBoxExtensionWrapper::GetDisplayInstantResults( // static v8::Handle<v8::Value> SearchBoxExtensionWrapper::GetThemeBackgroundInfo( const v8::Arguments& args) { - DVLOG(1) << "GetThemeBackgroundInfo"; content::RenderView* render_view = GetRenderView(); if (!render_view) return v8::Undefined(); + DVLOG(1) << render_view << " GetThemeBackgroundInfo"; const ThemeBackgroundInfo& theme_info = SearchBox::Get(render_view)->GetThemeBackgroundInfo(); v8::Handle<v8::Object> info = v8::Object::New(); @@ -547,7 +549,7 @@ v8::Handle<v8::Value> SearchBoxExtensionWrapper::GetThemeAreaHeight( content::RenderView* render_view = GetRenderView(); if (!render_view) return v8::Undefined(); - DVLOG(1) << "GetThemeAreaHeight: " + DVLOG(1) << render_view << " GetThemeAreaHeight: " << SearchBox::Get(render_view)->GetThemeAreaHeight(); return v8::Int32::New(SearchBox::Get(render_view)->GetThemeAreaHeight()); } @@ -580,10 +582,10 @@ v8::Handle<v8::Value> SearchBoxExtensionWrapper::NavigateContentWindow( // static v8::Handle<v8::Value> SearchBoxExtensionWrapper::SetSuggestions( const v8::Arguments& args) { - DVLOG(1) << "SetSuggestions"; content::RenderView* render_view = GetRenderView(); if (!render_view || !args.Length()) return v8::Undefined(); + DVLOG(1) << render_view << " SetSuggestions"; v8::Handle<v8::Object> suggestion_json = args[0]->ToObject(); InstantCompleteBehavior behavior = INSTANT_COMPLETE_NOW; @@ -619,10 +621,10 @@ v8::Handle<v8::Value> SearchBoxExtensionWrapper::SetSuggestions( // static v8::Handle<v8::Value> SearchBoxExtensionWrapper::SetQuerySuggestion( const v8::Arguments& args) { - DVLOG(1) << "SetQuerySuggestion"; content::RenderView* render_view = GetRenderView(); if (!render_view || args.Length() < 2) return v8::Undefined(); + DVLOG(1) << render_view << " SetQuerySuggestion"; string16 text = V8ValueToUTF16(args[0]); InstantCompleteBehavior behavior = INSTANT_COMPLETE_NOW; InstantSuggestionType type = INSTANT_SUGGESTION_URL; @@ -643,10 +645,10 @@ v8::Handle<v8::Value> SearchBoxExtensionWrapper::SetQuerySuggestion( v8::Handle<v8::Value> SearchBoxExtensionWrapper::SetQuerySuggestionFromAutocompleteResult( const v8::Arguments& args) { - DVLOG(1) << "SetQuerySuggestionFromAutocompleteResult"; content::RenderView* render_view = GetRenderView(); if (!render_view || !args.Length()) return v8::Undefined(); + DVLOG(1) << render_view << " SetQuerySuggestionFromAutocompleteResult"; const InstantAutocompleteResult* result = SearchBox::Get(render_view)-> GetAutocompleteResultWithId(args[0]->Uint32Value()); if (!result) return v8::Undefined(); @@ -666,10 +668,10 @@ v8::Handle<v8::Value> // static v8::Handle<v8::Value> SearchBoxExtensionWrapper::SetQuery( const v8::Arguments& args) { - DVLOG(1) << "SetQuery"; content::RenderView* render_view = GetRenderView(); if (!render_view || args.Length() < 2) return v8::Undefined(); + DVLOG(1) << render_view << " SetQuery"; string16 text = V8ValueToUTF16(args[0]); InstantCompleteBehavior behavior = INSTANT_COMPLETE_REPLACE; InstantSuggestionType type = INSTANT_SUGGESTION_SEARCH; @@ -687,10 +689,10 @@ v8::Handle<v8::Value> SearchBoxExtensionWrapper::SetQuery( v8::Handle<v8::Value> SearchBoxExtensionWrapper::SetQueryFromAutocompleteResult( const v8::Arguments& args) { - DVLOG(1) << "SetQueryFromAutocompleteResult"; content::RenderView* render_view = GetRenderView(); if (!render_view || !args.Length()) return v8::Undefined(); + DVLOG(1) << render_view << " SetQueryFromAutocompleteResult"; const InstantAutocompleteResult* result = SearchBox::Get(render_view)-> GetAutocompleteResultWithId(args[0]->Uint32Value()); if (!result) return v8::Undefined(); @@ -712,10 +714,10 @@ v8::Handle<v8::Value> // static v8::Handle<v8::Value> SearchBoxExtensionWrapper::Show( const v8::Arguments& args) { - DVLOG(1) << "ShowInstantPreview"; content::RenderView* render_view = GetRenderView(); if (!render_view || args.Length() < 2) return v8::Undefined(); + DVLOG(1) << render_view << " ShowInstantPreview"; InstantShownReason reason = INSTANT_SHOWN_NOT_SPECIFIED; switch (args[0]->Uint32Value()) { case 1: reason = INSTANT_SHOWN_CUSTOM_NTP_CONTENT; break; @@ -737,7 +739,6 @@ v8::Handle<v8::Value> SearchBoxExtensionWrapper::Show( // static void SearchBoxExtension::DispatchChange(WebKit::WebFrame* frame) { - DVLOG(1) << "DispatchChange"; Dispatch(frame, kDispatchChangeEventScript); } @@ -762,21 +763,11 @@ bool SearchBoxExtension::PageSupportsInstant(WebKit::WebFrame* frame) { v8::Handle<v8::Value> v = frame->executeScriptAndReturnValue( WebKit::WebScriptSource(kSupportsInstantScript)); - bool supports_instant = !v.IsEmpty() && v->BooleanValue(); - - // Send a resize message to tell the page that Chrome is actively using the - // searchbox API with it. The page uses the message to transition from - // "homepage" mode to "search" mode. - if (supports_instant) - DispatchResize(frame); - - DVLOG(1) << "PageSupportsInstant: " << supports_instant; - return supports_instant; + return !v.IsEmpty() && v->BooleanValue(); } // static void SearchBoxExtension::DispatchAutocompleteResults(WebKit::WebFrame* frame) { - DVLOG(1) << "DispatchAutocompleteResults"; Dispatch(frame, kDispatchAutocompleteResultsEventScript); } @@ -790,7 +781,6 @@ void SearchBoxExtension::DispatchUpOrDownKeyPress(WebKit::WebFrame* frame, // static void SearchBoxExtension::DispatchContextChange(WebKit::WebFrame* frame) { - DVLOG(1) << "DispatchContextChange"; Dispatch(frame, kDispatchContextChangeEventScript); } diff --git a/chrome/renderer/searchbox/searchbox_extension.h b/chrome/renderer/searchbox/searchbox_extension.h index 98ef343..a09c857 100644 --- a/chrome/renderer/searchbox/searchbox_extension.h +++ b/chrome/renderer/searchbox/searchbox_extension.h @@ -1,4 +1,4 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. diff --git a/chrome/test/functional/instant.py b/chrome/test/functional/instant.py index 139230be..d52593b 100755 --- a/chrome/test/functional/instant.py +++ b/chrome/test/functional/instant.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Copyright 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. |