diff options
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. |