summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorsky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-08-11 04:03:57 +0000
committersky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-08-11 04:03:57 +0000
commitfd2b9cec9b6eed50f8fc1fcdf72866733fe57f45 (patch)
tree620a3ff359c4007f30c54f292de5a546739a570a /chrome
parent7ab36c4f07b585449febcc6f2c59a9f5a0a40eed (diff)
downloadchromium_src-fd2b9cec9b6eed50f8fc1fcdf72866733fe57f45.zip
chromium_src-fd2b9cec9b6eed50f8fc1fcdf72866733fe57f45.tar.gz
chromium_src-fd2b9cec9b6eed50f8fc1fcdf72866733fe57f45.tar.bz2
Adds support for showing the match preview on views. It's behind the
flag --enable-match-preview. There is still a lot of details to get it working good enough, but this is a good point to check some stuff in. BUG=none TEST=none Review URL: http://codereview.chromium.org/3105004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@55665 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/browser.cc11
-rw-r--r--chrome/browser/browser.h1
-rw-r--r--chrome/browser/tab_contents/match_preview.cc192
-rw-r--r--chrome/browser/tab_contents/match_preview.h80
-rw-r--r--chrome/browser/tab_contents/tab_contents.cc4
-rw-r--r--chrome/browser/tab_contents/tab_contents.h6
-rw-r--r--chrome/browser/tab_contents/tab_contents_delegate.cc3
-rw-r--r--chrome/browser/tab_contents/tab_contents_delegate.h5
-rw-r--r--chrome/browser/tabs/tab_strip_model.cc43
-rw-r--r--chrome/browser/tabs/tab_strip_model.h37
-rw-r--r--chrome/browser/views/frame/browser_view.cc217
-rw-r--r--chrome/browser/views/frame/browser_view.h28
-rw-r--r--chrome/browser/views/location_bar/location_bar_view.cc8
-rw-r--r--chrome/chrome_browser.gypi4
-rw-r--r--chrome/common/chrome_switches.cc3
-rw-r--r--chrome/common/chrome_switches.h1
-rw-r--r--chrome/common/notification_type.h4
17 files changed, 602 insertions, 45 deletions
diff --git a/chrome/browser/browser.cc b/chrome/browser/browser.cc
index 83c6c48..6083fb0 100644
--- a/chrome/browser/browser.cc
+++ b/chrome/browser/browser.cc
@@ -70,6 +70,7 @@
#include "chrome/browser/sync/sync_ui_util.h"
#include "chrome/browser/tab_closeable_state_watcher.h"
#include "chrome/browser/tab_contents/interstitial_page.h"
+#include "chrome/browser/tab_contents/match_preview.h"
#include "chrome/browser/tab_contents/navigation_controller.h"
#include "chrome/browser/tab_contents/navigation_entry.h"
#include "chrome/browser/tab_contents/tab_contents.h"
@@ -2944,6 +2945,16 @@ void Browser::ContentTypeChanged(TabContents* source) {
UpdateZoomCommandsForTabState();
}
+void Browser::CommitMatchPreview(TabContents* source) {
+ int index = tabstrip_model_.GetIndexOfTabContents(source);
+ DCHECK_NE(-1, index);
+ TabContents* preview_contents =
+ source->match_preview()->ReleasePreviewContents();
+ // TabStripModel takes ownership of preview_contents.
+ tabstrip_model_.ReplaceTabContentsAt(
+ index, preview_contents, TabStripModelObserver::REPLACE_MATCH_PREVIEW);
+}
+
///////////////////////////////////////////////////////////////////////////////
// Browser, SelectFileDialog::Listener implementation:
diff --git a/chrome/browser/browser.h b/chrome/browser/browser.h
index 1041735..0a7c0ab 100644
--- a/chrome/browser/browser.h
+++ b/chrome/browser/browser.h
@@ -741,6 +741,7 @@ class Browser : public TabStripModelDelegate,
int32 page_id);
virtual Browser* GetBrowser();
virtual void ContentTypeChanged(TabContents* source);
+ virtual void CommitMatchPreview(TabContents* source);
// Overridden from SelectFileDialog::Listener:
virtual void FileSelected(const FilePath& path, int index, void* params);
diff --git a/chrome/browser/tab_contents/match_preview.cc b/chrome/browser/tab_contents/match_preview.cc
new file mode 100644
index 0000000..3c0c43e
--- /dev/null
+++ b/chrome/browser/tab_contents/match_preview.cc
@@ -0,0 +1,192 @@
+// Copyright (c) 2010 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/tab_contents/match_preview.h"
+
+#include <algorithm>
+
+#include "base/command_line.h"
+#include "chrome/browser/tab_contents/navigation_controller.h"
+#include "chrome/browser/tab_contents/navigation_entry.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/tab_contents/tab_contents_delegate.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/page_transition_types.h"
+#include "chrome/common/renderer_preferences.h"
+#include "ipc/ipc_message.h"
+
+class MatchPreview::TabContentsDelegateImpl : public TabContentsDelegate {
+ public:
+ explicit TabContentsDelegateImpl(MatchPreview* match_preview)
+ : match_preview_(match_preview) {
+ }
+
+ virtual void OpenURLFromTab(TabContents* source,
+ const GURL& url, const GURL& referrer,
+ WindowOpenDisposition disposition,
+ PageTransition::Type transition) {}
+ virtual void NavigationStateChanged(const TabContents* source,
+ unsigned changed_flags) {}
+ virtual void AddNewContents(TabContents* source,
+ TabContents* new_contents,
+ WindowOpenDisposition disposition,
+ const gfx::Rect& initial_pos,
+ bool user_gesture) {}
+ virtual void ActivateContents(TabContents* contents) {
+ match_preview_->CommitCurrentPreview();
+ }
+ virtual void LoadingStateChanged(TabContents* source) {}
+ virtual void CloseContents(TabContents* source) {}
+ virtual void MoveContents(TabContents* source, const gfx::Rect& pos) {}
+ virtual void DetachContents(TabContents* source) {}
+ virtual bool IsPopup(const TabContents* source) const {
+ return false;
+ }
+ virtual TabContents* GetConstrainingContents(TabContents* source) {
+ return NULL;
+ }
+ virtual void ToolbarSizeChanged(TabContents* source, bool is_animating) {}
+ virtual void URLStarredChanged(TabContents* source, bool starred) {}
+ virtual void UpdateTargetURL(TabContents* source, const GURL& url) {}
+ virtual void ContentsMouseEvent(
+ TabContents* source, const gfx::Point& location, bool motion) {}
+ virtual void ContentsZoomChange(bool zoom_in) {}
+ virtual void OnContentSettingsChange(TabContents* source) {}
+ virtual bool IsApplication() const { return false; }
+ virtual void ConvertContentsToApplication(TabContents* source) {}
+ virtual bool CanReloadContents(TabContents* source) const { return true; }
+ virtual gfx::Rect GetRootWindowResizerRect() const {
+ return match_preview_->host_->delegate() ?
+ match_preview_->host_->delegate()->GetRootWindowResizerRect() :
+ gfx::Rect();
+ }
+ virtual void ShowHtmlDialog(HtmlDialogUIDelegate* delegate,
+ gfx::NativeWindow parent_window) {}
+ virtual void BeforeUnloadFired(TabContents* tab,
+ bool proceed,
+ bool* proceed_to_fire_unload) {}
+ virtual void ForwardMessageToExternalHost(const std::string& message,
+ const std::string& origin,
+ const std::string& target) {}
+ virtual bool IsExternalTabContainer() const { return false; }
+ virtual void SetFocusToLocationBar(bool select_all) {}
+ virtual void RenderWidgetShowing() {}
+ virtual ExtensionFunctionDispatcher* CreateExtensionFunctionDispatcher(
+ RenderViewHost* render_view_host,
+ const std::string& extension_id) {
+ return NULL;
+ }
+ virtual bool TakeFocus(bool reverse) { return false; }
+ virtual void SetTabContentBlocked(TabContents* contents, bool blocked) {}
+ virtual void TabContentsFocused(TabContents* tab_content) {
+ match_preview_->CommitCurrentPreview();
+ }
+ virtual int GetExtraRenderViewHeight() const { return 0; }
+ virtual bool CanDownload(int request_id) { return false; }
+ virtual void OnStartDownload(DownloadItem* download, TabContents* tab) {}
+ virtual bool HandleContextMenu(const ContextMenuParams& params) {
+ return false;
+ }
+ virtual bool ExecuteContextMenuCommand(int command) {
+ return false;
+ }
+ virtual void ConfirmAddSearchProvider(const TemplateURL* template_url,
+ Profile* profile) {}
+ virtual void ShowPageInfo(Profile* profile,
+ const GURL& url,
+ const NavigationEntry::SSLStatus& ssl,
+ bool show_history) {}
+ virtual bool PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event,
+ bool* is_keyboard_shortcut) {
+ return false;
+ }
+ virtual void HandleKeyboardEvent(const NativeWebKeyboardEvent& event) {}
+ virtual void ShowRepostFormWarningDialog(TabContents* tab_contents) {}
+ virtual void ShowContentSettingsWindow(ContentSettingsType content_type) {}
+ virtual void ShowCollectedCookiesDialog(TabContents* tab_contents) {}
+ virtual bool OnGoToEntryOffset(int offset) { return false; }
+ virtual bool ShouldAddNavigationsToHistory() const { return false; }
+ virtual void OnDidGetApplicationInfo(TabContents* tab_contents,
+ int32 page_id) {}
+ virtual Browser* GetBrowser() { return NULL; }
+ virtual gfx::NativeWindow GetFrameNativeWindow() {
+ return match_preview_->host_->delegate() ?
+ match_preview_->host_->delegate()->GetFrameNativeWindow() : NULL;
+ }
+ virtual void TabContentsCreated(TabContents* new_contents) {}
+ virtual bool infobars_enabled() { return false; }
+ virtual bool ShouldEnablePreferredSizeNotifications() { return false; }
+ virtual void UpdatePreferredSize(const gfx::Size& pref_size) {}
+ virtual void ContentTypeChanged(TabContents* source) {}
+
+ private:
+ MatchPreview* match_preview_;
+
+ DISALLOW_COPY_AND_ASSIGN(TabContentsDelegateImpl);
+};
+
+MatchPreview::MatchPreview(TabContents* host) : host_(host) {
+ delegate_.reset(new TabContentsDelegateImpl(this));
+}
+
+MatchPreview::~MatchPreview() {
+ // Delete the TabContents before the delegate as the TabContents holds a
+ // reference to the delegate.
+ preview_contents_.reset(NULL);
+}
+
+// static
+bool MatchPreview::IsEnabled() {
+ static bool enabled = false;
+ static bool checked = false;
+ if (!checked) {
+ checked = true;
+ enabled = CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableMatchPreview);
+ }
+ return enabled;
+}
+
+void MatchPreview::Update(const GURL& url) {
+ if (url_ == url)
+ return;
+
+ url_ = url;
+
+ if (url_.is_empty() || !url_.is_valid()) {
+ DestroyPreviewContents();
+ return;
+ }
+
+ if (!preview_contents_.get()) {
+ preview_contents_.reset(
+ new TabContents(host_->profile(), NULL, MSG_ROUTING_NONE, NULL));
+ preview_contents_->set_delegate(delegate_.get());
+ NotificationService::current()->Notify(
+ NotificationType::MATCH_PREVIEW_TAB_CONTENTS_CREATED,
+ Source<TabContents>(host_),
+ NotificationService::NoDetails());
+ }
+
+ // TODO: figure out transition type.
+ preview_contents_->controller().LoadURL(url, GURL(),
+ PageTransition::GENERATED);
+}
+
+void MatchPreview::DestroyPreviewContents() {
+ url_ = GURL();
+ preview_contents_.reset(NULL);
+}
+
+void MatchPreview::CommitCurrentPreview() {
+ DCHECK(preview_contents_.get());
+ if (host_->delegate())
+ host_->delegate()->CommitMatchPreview(host_);
+}
+
+TabContents* MatchPreview::ReleasePreviewContents() {
+ url_ = GURL();
+ return preview_contents_.release();
+}
diff --git a/chrome/browser/tab_contents/match_preview.h b/chrome/browser/tab_contents/match_preview.h
new file mode 100644
index 0000000..cc6605b
--- /dev/null
+++ b/chrome/browser/tab_contents/match_preview.h
@@ -0,0 +1,80 @@
+// Copyright (c) 2010 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_TAB_CONTENTS_MATCH_PREVIEW_H_
+#define CHROME_BROWSER_TAB_CONTENTS_MATCH_PREVIEW_H_
+
+#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
+#include "googleurl/src/gurl.h"
+
+class TabContents;
+
+// MatchPreview maintains a TabContents that is intended to give a preview of
+// a URL. MatchPreview is owned by TabContents.
+//
+// As the user types in the omnibox the LocationBar updates MatchPreview by
+// way of 'Update'. If the user does a gesture on the preview, say clicks a
+// link, the TabContentsDelegate of the hosting TabContents is notified with
+// CommitMatchPreview and the TabContents maintained by MatchPreview replaces
+// the current TabContents in the TabStripModel.
+//
+// At any time the TabContents maintained by MatchPreview may be destroyed by
+// way of 'DestroyPreviewContents'. Consumers of MatchPreview can detect the
+// preview TabContents was destroyed by observing TAB_CONTENTS_DESTROYED.
+//
+// Consumers of MatchPreview can detect a new TabContents was created by
+// MatchPreview by listening for MATCH_PREVIEW_TAB_CONTENTS_CREATED.
+class MatchPreview {
+ public:
+ explicit MatchPreview(TabContents* host);
+ ~MatchPreview();
+
+ // Is MatchPreview enabled?
+ static bool IsEnabled();
+
+ // Invoked as the user types in the omnibox with the url to navigate to. If
+ // the url is empty and there is a preview TabContents it is destroyed. If url
+ // is non-empty and the preview TabContents has not been created it is
+ // created.
+ void Update(const GURL& url);
+
+ // Destroys the preview TabContents. Does nothing if the preview TabContents
+ // has not been created.
+ void DestroyPreviewContents();
+
+ // Invoked when the user does some gesture that should trigger making the
+ // current previewed page the permanent page.
+ void CommitCurrentPreview();
+
+ // Releases the preview TabContents passing ownership to the caller. This is
+ // intended to be called when the preview TabContents is committed.
+ TabContents* ReleasePreviewContents();
+
+ // The TabContents we're maintaining the preview for.
+ TabContents* host() { return host_; }
+
+ // The preview TabContents; may be null.
+ TabContents* preview_contents() { return preview_contents_.get(); }
+
+ private:
+ class TabContentsDelegateImpl;
+
+ // The url we're displaying.
+ GURL url_;
+
+ // The TabContents we're providing the preview for.
+ TabContents* host_;
+
+ // Delegate of the preview TabContents. Used to detect when the user does some
+ // gesture on the TabContents and the preview needs to be activated.
+ scoped_ptr<TabContentsDelegateImpl> delegate_;
+
+ // The preview TabContents; may be null.
+ scoped_ptr<TabContents> preview_contents_;
+
+ DISALLOW_COPY_AND_ASSIGN(MatchPreview);
+};
+
+#endif // CHROME_BROWSER_TAB_CONTENTS_MATCH_PREVIEW_H_
diff --git a/chrome/browser/tab_contents/tab_contents.cc b/chrome/browser/tab_contents/tab_contents.cc
index 42da773..076ced4 100644
--- a/chrome/browser/tab_contents/tab_contents.cc
+++ b/chrome/browser/tab_contents/tab_contents.cc
@@ -69,6 +69,7 @@
#include "chrome/browser/sessions/session_types.h"
#include "chrome/browser/tab_contents/infobar_delegate.h"
#include "chrome/browser/tab_contents/interstitial_page.h"
+#include "chrome/browser/tab_contents/match_preview.h"
#include "chrome/browser/tab_contents/navigation_entry.h"
#include "chrome/browser/tab_contents/provisional_load_details.h"
#include "chrome/browser/tab_contents/tab_contents_delegate.h"
@@ -424,6 +425,9 @@ TabContents::TabContents(Profile* profile,
// Set-up the showing of the omnibox search infobar if applicable.
if (OmniboxSearchHint::IsEnabled(profile))
omnibox_search_hint_.reset(new OmniboxSearchHint(this));
+
+ if (MatchPreview::IsEnabled())
+ match_preview_.reset(new MatchPreview(this));
}
TabContents::~TabContents() {
diff --git a/chrome/browser/tab_contents/tab_contents.h b/chrome/browser/tab_contents/tab_contents.h
index ab4cf56..ac73e96 100644
--- a/chrome/browser/tab_contents/tab_contents.h
+++ b/chrome/browser/tab_contents/tab_contents.h
@@ -68,6 +68,7 @@ class DownloadItem;
class Extension;
class InfoBarDelegate;
class LoadNotificationDetails;
+class MatchPreview;
class OmniboxSearchHint;
class PasswordManager;
class PluginInstaller;
@@ -160,6 +161,9 @@ class TabContents : public PageNavigator,
// Returns the TabContentsSSLHelper, creating if it necessary.
TabContentsSSLHelper* GetSSLHelper();
+ // Returns the MatchPreview. Returns NULL if MatchPreview is not enabled.
+ MatchPreview* match_preview() { return match_preview_.get(); }
+
// Returns the SavePackage which manages the page saving job. May be NULL.
SavePackage* save_package() const { return save_package_.get(); }
@@ -1261,6 +1265,8 @@ class TabContents : public PageNavigator,
// See description in RenderViewHostDelegate::SetDisplayingPDFContent.
bool displaying_pdf_content_;
+ scoped_ptr<MatchPreview> match_preview_;
+
// ---------------------------------------------------------------------------
DISALLOW_COPY_AND_ASSIGN(TabContents);
diff --git a/chrome/browser/tab_contents/tab_contents_delegate.cc b/chrome/browser/tab_contents/tab_contents_delegate.cc
index 30bee94..9c89cd3 100644
--- a/chrome/browser/tab_contents/tab_contents_delegate.cc
+++ b/chrome/browser/tab_contents/tab_contents_delegate.cc
@@ -167,5 +167,8 @@ void TabContentsDelegate::UpdatePreferredSize(const gfx::Size& pref_size) {
void TabContentsDelegate::ContentTypeChanged(TabContents* source) {
}
+void TabContentsDelegate::CommitMatchPreview(TabContents* source) {
+}
+
TabContentsDelegate::~TabContentsDelegate() {
}
diff --git a/chrome/browser/tab_contents/tab_contents_delegate.h b/chrome/browser/tab_contents/tab_contents_delegate.h
index 9b2230e..a6b2597 100644
--- a/chrome/browser/tab_contents/tab_contents_delegate.h
+++ b/chrome/browser/tab_contents/tab_contents_delegate.h
@@ -277,6 +277,11 @@ class TabContentsDelegate : public AutomationResourceRoutingDelegate {
// PDF using the internal PDF plugin.
virtual void ContentTypeChanged(TabContents* source);
+ // Sent when the user does a gesture that results in committing the match
+ // preview. The delegate should replace |source| with the |source|'s match
+ // preview TabContents.
+ virtual void CommitMatchPreview(TabContents* source);
+
protected:
virtual ~TabContentsDelegate();
};
diff --git a/chrome/browser/tabs/tab_strip_model.cc b/chrome/browser/tabs/tab_strip_model.cc
index 8ac8fc4..269de35 100644
--- a/chrome/browser/tabs/tab_strip_model.cc
+++ b/chrome/browser/tabs/tab_strip_model.cc
@@ -82,6 +82,13 @@ void TabStripModelObserver::TabReplacedAt(TabContents* old_contents,
int index) {
}
+void TabStripModelObserver::TabReplacedAt(TabContents* old_contents,
+ TabContents* new_contents,
+ int index,
+ TabReplaceType type) {
+ TabReplacedAt(old_contents, new_contents, index);
+}
+
void TabStripModelObserver::TabPinnedStateChanged(TabContents* contents,
int index) {
}
@@ -233,6 +240,13 @@ void TabStripModel::InsertTabContentsAt(int index,
ChangeSelectedContentsFrom(selected_contents, index, false);
}
+void TabStripModel::ReplaceTabContentsAt(
+ int index,
+ TabContents* new_contents,
+ TabStripModelObserver::TabReplaceType type) {
+ delete ReplaceTabContentsAtImpl(index, new_contents, type);
+}
+
void TabStripModel::ReplaceNavigationControllerAt(
int index, NavigationController* controller) {
// This appears to be OK with no flicker since no redraw event
@@ -1043,14 +1057,10 @@ bool TabStripModel::ShouldMakePhantomOnClose(int index) {
}
void TabStripModel::MakePhantom(int index) {
- TabContents* old_contents = GetContentsAt(index);
- TabContents* new_contents = old_contents->CloneAndMakePhantom();
-
- contents_data_[index]->contents = new_contents;
-
- // And notify observers.
- FOR_EACH_OBSERVER(TabStripModelObserver, observers_,
- TabReplacedAt(old_contents, new_contents, index));
+ // MakePhantom is called when the TabContents is being destroyed so we don't
+ // need to do anything with the returned value from ReplaceTabContentsAtImpl.
+ ReplaceTabContentsAtImpl(index, GetContentsAt(index)->CloneAndMakePhantom(),
+ TabStripModelObserver::REPLACE_MADE_PHANTOM);
if (selected_index_ == index && HasNonPhantomTabs()) {
// Change the selection, otherwise we're going to force the phantom tab
@@ -1095,3 +1105,20 @@ bool TabStripModel::OpenerMatches(const TabContentsData* data,
bool use_group) {
return data->opener == opener || (use_group && data->group == opener);
}
+
+TabContents* TabStripModel::ReplaceTabContentsAtImpl(
+ int index,
+ TabContents* new_contents,
+ TabStripModelObserver::TabReplaceType type) {
+ // TODO: this should reset group/opener of any tabs that point at
+ // old_contents.
+ DCHECK(ContainsIndex(index));
+
+ TabContents* old_contents = GetContentsAt(index);
+
+ contents_data_[index]->contents = new_contents;
+
+ FOR_EACH_OBSERVER(TabStripModelObserver, observers_,
+ TabReplacedAt(old_contents, new_contents, index, type));
+ return old_contents;
+}
diff --git a/chrome/browser/tabs/tab_strip_model.h b/chrome/browser/tabs/tab_strip_model.h
index f26af59..542b27f 100644
--- a/chrome/browser/tabs/tab_strip_model.h
+++ b/chrome/browser/tabs/tab_strip_model.h
@@ -54,6 +54,18 @@ class TabStripModelObserver {
ALL
};
+ // Enum used by ReplaceTabContentsAt.
+ // TODO(sky): TabReplaceType should be declared outside the scope of
+ // the observer. I need to put all the enums in a namespace and cleanup this
+ // file.
+ enum TabReplaceType {
+ // The replace is the result of the tab being made phantom.
+ REPLACE_MADE_PHANTOM,
+
+ // The replace is the result of the match preview being committed.
+ REPLACE_MATCH_PREVIEW
+ };
+
// A new TabContents was inserted into the TabStripModel at the specified
// index. |foreground| is whether or not it was opened in the foreground
// (selected).
@@ -100,8 +112,18 @@ class TabStripModelObserver {
// The tab contents was replaced at the specified index. This is invoked when
// a tab becomes phantom. See description of phantom tabs in class description
// of TabStripModel for details.
+ // TODO(sky): nuke this in favor of the 4 arg variant.
+ virtual void TabReplacedAt(TabContents* old_contents,
+ TabContents* new_contents,
+ int index);
+
+ // The tab contents was replaced at the specified index. |type| describes
+ // the type of replace.
+ // This invokes TabReplacedAt with three args.
virtual void TabReplacedAt(TabContents* old_contents,
- TabContents* new_contents, int index);
+ TabContents* new_contents,
+ int index,
+ TabReplaceType type);
// Invoked when the pinned state of a tab changes. This is not invoked if the
// tab ends up moving as a result of the mini state changing.
@@ -433,6 +455,12 @@ class TabStripModel : public NotificationObserver {
void ReplaceNavigationControllerAt(int index,
NavigationController* controller);
+ // Replaces the tab contents at |index| with |new_contents|. |type| is passed
+ // to the observer. This deletes the TabContents currently at |index|.
+ void ReplaceTabContentsAt(int index,
+ TabContents* new_contents,
+ TabStripModelObserver::TabReplaceType type);
+
// Detaches the TabContents at the specified index from this strip. The
// TabContents is not destroyed, just removed from display. The caller is
// responsible for doing something with it (e.g. stuffing it into another
@@ -725,6 +753,13 @@ class TabStripModel : public NotificationObserver {
const NavigationController* opener,
bool use_group);
+ // Does the work for ReplaceTabContentsAt returning the old TabContents.
+ // The caller owns the returned TabContents.
+ TabContents* ReplaceTabContentsAtImpl(
+ int index,
+ TabContents* new_contents,
+ TabStripModelObserver::TabReplaceType type);
+
// Our delegate.
TabStripModelDelegate* delegate_;
diff --git a/chrome/browser/views/frame/browser_view.cc b/chrome/browser/views/frame/browser_view.cc
index 3034a38..8c1189c 100644
--- a/chrome/browser/views/frame/browser_view.cc
+++ b/chrome/browser/views/frame/browser_view.cc
@@ -15,6 +15,8 @@
#include "base/utf_string_conversions.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/app_modal_dialog_queue.h"
+#include "chrome/browser/autocomplete/autocomplete_popup_model.h"
+#include "chrome/browser/autocomplete/autocomplete_popup_view.h"
#include "chrome/browser/automation/ui_controls.h"
#include "chrome/browser/bookmarks/bookmark_utils.h"
#include "chrome/browser/browser_list.h"
@@ -27,6 +29,7 @@
#include "chrome/browser/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/sessions/tab_restore_service.h"
+#include "chrome/browser/tab_contents/match_preview.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_view.h"
#include "chrome/browser/view_ids.h"
@@ -127,6 +130,71 @@ static gfx::NativeWindow GetNormalBrowserWindowForBrowser(Browser* browser,
}
#endif // defined(OS_CHROMEOS)
+// ContentsContainer is responsible for managing the TabContents views.
+// ContentsContainer has up to two children: one for the currently active
+// TabContents and one for the match preview TabContents.
+class BrowserView::ContentsContainer : public views::View {
+ public:
+ ContentsContainer(BrowserView* browser_view, views::View* active)
+ : browser_view_(browser_view),
+ active_(active),
+ preview_(NULL) {
+ AddChildView(active_);
+ }
+
+ // Makes the preview view the active view and nulls out the old active view.
+ // It's assumed the caller will delete or remove the old active view
+ // separately.
+ void MakePreviewContentsActiveContents() {
+ active_ = preview_;
+ preview_ = NULL;
+ Layout();
+ }
+
+ // Sets the preview view. This does not delete the old.
+ void SetPreview(views::View* preview) {
+ if (preview == preview_)
+ return;
+
+ if (preview_)
+ RemoveChildView(preview_);
+ preview_ = preview;
+ if (preview_)
+ AddChildView(preview_);
+
+ Layout();
+ }
+
+ virtual void Layout() {
+ // The active view always gets the full bounds.
+ active_->SetBounds(0, 0, width(), height());
+
+ if (preview_) {
+ // The preview view gets the full width and is positioned beneath the
+ // bottom of the autocompleted popup.
+ int max_autocomplete_y = browser_view_->toolbar()->location_bar()->
+ location_entry()->model()->popup_model()->view()->GetMaxYCoordinate();
+ gfx::Point screen_origin;
+ views::View::ConvertPointToScreen(this, &screen_origin);
+ DCHECK_GT(max_autocomplete_y, screen_origin.y());
+ int preview_origin = max_autocomplete_y - screen_origin.y();
+ if (preview_origin < height()) {
+ preview_->SetBounds(0, preview_origin, width(),
+ height() - preview_origin);
+ } else {
+ preview_->SetBounds(0, 0, 0, 0);
+ }
+ }
+ }
+
+ private:
+ BrowserView* browser_view_;
+ views::View* active_;
+ views::View* preview_;
+
+ DISALLOW_COPY_AND_ASSIGN(ContentsContainer);
+};
+
///////////////////////////////////////////////////////////////////////////////
// BookmarkExtensionBackground, private:
// This object serves as the views::Background object which is used to layout
@@ -416,6 +484,8 @@ BrowserView::BrowserView(Browser* browser)
infobar_container_(NULL),
contents_container_(NULL),
devtools_container_(NULL),
+ preview_container_(NULL),
+ contents_(NULL),
contents_split_(NULL),
initialized_(false),
ignore_layout_(true),
@@ -518,7 +588,7 @@ gfx::Rect BrowserView::GetToolbarBounds() const {
}
gfx::Rect BrowserView::GetClientAreaBounds() const {
- gfx::Rect container_bounds = contents_container_->bounds();
+ gfx::Rect container_bounds = contents_->bounds();
gfx::Point container_origin = container_bounds.origin();
ConvertPointToView(this, GetParent(), &container_origin);
container_bounds.set_origin(container_origin);
@@ -1320,12 +1390,36 @@ ToolbarView* BrowserView::GetToolbarView() const {
void BrowserView::Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
- if (type == NotificationType::PREF_CHANGED &&
- *Details<std::string>(details).ptr() == prefs::kShowBookmarkBar) {
- if (MaybeShowBookmarkBar(browser_->GetSelectedTabContents()))
- Layout();
- } else {
- NOTREACHED() << "Got a notification we didn't register for!";
+ switch (type.value) {
+ case NotificationType::PREF_CHANGED:
+ if (*Details<std::string>(details).ptr() == prefs::kShowBookmarkBar &&
+ MaybeShowBookmarkBar(browser_->GetSelectedTabContents())) {
+ Layout();
+ }
+ break;
+
+ case NotificationType::MATCH_PREVIEW_TAB_CONTENTS_CREATED:
+ if (Source<TabContents>(source).ptr() ==
+ browser_->GetSelectedTabContents()) {
+ ShowMatchPreview();
+ }
+ break;
+
+ case NotificationType::TAB_CONTENTS_DESTROYED: {
+ if (MatchPreview::IsEnabled()) {
+ TabContents* selected_contents = browser_->GetSelectedTabContents();
+ if (selected_contents &&
+ selected_contents->match_preview()->preview_contents() ==
+ Source<TabContents>(source).ptr()) {
+ HideMatchPreview();
+ }
+ }
+ break;
+ }
+
+ default:
+ NOTREACHED() << "Got a notification we didn't register for!";
+ break;
}
}
@@ -1360,34 +1454,29 @@ void BrowserView::TabSelectedAt(TabContents* old_contents,
bool user_gesture) {
DCHECK(old_contents != new_contents);
- // Update various elements that are interested in knowing the current
- // TabContents.
-
- // When we toggle the NTP floating bookmarks bar and/or the info bar,
- // we don't want any TabContents to be attached, so that we
- // avoid an unnecessary resize and re-layout of a TabContents.
- contents_container_->ChangeTabContents(NULL);
- infobar_container_->ChangeTabContents(new_contents);
- UpdateUIForContents(new_contents);
- contents_container_->ChangeTabContents(new_contents);
+ ProcessTabSelected(new_contents, true);
+}
- UpdateDevToolsForContents(new_contents);
- // TODO(beng): This should be called automatically by ChangeTabContents, but I
- // am striving for parity now rather than cleanliness. This is
- // required to make features like Duplicate Tab, Undo Close Tab,
- // etc not result in sad tab.
- new_contents->DidBecomeSelected();
- if (BrowserList::GetLastActive() == browser_ &&
- !browser_->tabstrip_model()->closing_all() && GetWindow()->IsVisible()) {
- // We only restore focus if our window is visible, to avoid invoking blur
- // handlers when we are eventually shown.
- new_contents->view()->RestoreFocus();
+void BrowserView::TabReplacedAt(TabContents* old_contents,
+ TabContents* new_contents,
+ int index,
+ TabStripModelObserver::TabReplaceType type) {
+ if (type != TabStripModelObserver::REPLACE_MATCH_PREVIEW ||
+ index != browser_->tabstrip_model()->selected_index()) {
+ return;
}
- // Update all the UI bits.
- UpdateTitleBar();
- UpdateToolbar(new_contents, true);
- UpdateUIForContents(new_contents);
+ // Swap the 'active' and 'preview' and delete what was the active.
+ contents_->MakePreviewContentsActiveContents();
+ TabContentsContainer* old_container = contents_container_;
+ contents_container_ = preview_container_;
+ old_container->ChangeTabContents(NULL);
+ delete old_container;
+ preview_container_ = NULL;
+
+ // Update the UI for what was the preview contents and is now active. Pass in
+ // false to ProcessTabSelected as new_contents is already parented correctly.
+ ProcessTabSelected(new_contents, false);
}
void BrowserView::TabStripEmpty() {
@@ -1759,11 +1848,12 @@ void BrowserView::Init() {
AddChildView(infobar_container_);
contents_container_ = new TabContentsContainer;
+ contents_ = new ContentsContainer(this, contents_container_);
devtools_container_ = new TabContentsContainer;
devtools_container_->SetID(VIEW_ID_DEV_TOOLS_DOCKED);
devtools_container_->SetVisible(false);
contents_split_ = new views::SingleSplitView(
- contents_container_,
+ contents_,
devtools_container_,
views::SingleSplitView::VERTICAL_SPLIT);
contents_split_->SetID(VIEW_ID_CONTENTS_SPLIT);
@@ -1808,6 +1898,13 @@ void BrowserView::Init() {
// We're now initialized and ready to process Layout requests.
ignore_layout_ = false;
+
+ registrar_.Add(this,
+ NotificationType::MATCH_PREVIEW_TAB_CONTENTS_CREATED,
+ NotificationService::AllSources());
+ registrar_.Add(this,
+ NotificationType::TAB_CONTENTS_DESTROYED,
+ NotificationService::AllSources());
}
#if defined(OS_WIN)
@@ -2234,6 +2331,60 @@ void BrowserView::InitHangMonitor() {
#endif
}
+void BrowserView::ShowMatchPreview() {
+ if (!preview_container_)
+ preview_container_ = new TabContentsContainer();
+ contents_->SetPreview(preview_container_);
+ preview_container_->ChangeTabContents(
+ browser_->GetSelectedTabContents()->match_preview()->preview_contents());
+}
+
+void BrowserView::HideMatchPreview() {
+ if (!preview_container_)
+ return;
+
+ // The contents must be changed before SetPreview is invoked.
+ preview_container_->ChangeTabContents(NULL);
+ contents_->SetPreview(NULL);
+ delete preview_container_;
+ preview_container_ = NULL;
+}
+
+void BrowserView::ProcessTabSelected(TabContents* new_contents,
+ bool change_tab_contents) {
+
+ // Update various elements that are interested in knowing the current
+ // TabContents.
+
+ // When we toggle the NTP floating bookmarks bar and/or the info bar,
+ // we don't want any TabContents to be attached, so that we
+ // avoid an unnecessary resize and re-layout of a TabContents.
+ if (change_tab_contents)
+ contents_container_->ChangeTabContents(NULL);
+ infobar_container_->ChangeTabContents(new_contents);
+ UpdateUIForContents(new_contents);
+ if (change_tab_contents)
+ contents_container_->ChangeTabContents(new_contents);
+
+ UpdateDevToolsForContents(new_contents);
+ // TODO(beng): This should be called automatically by ChangeTabContents, but I
+ // am striving for parity now rather than cleanliness. This is
+ // required to make features like Duplicate Tab, Undo Close Tab,
+ // etc not result in sad tab.
+ new_contents->DidBecomeSelected();
+ if (BrowserList::GetLastActive() == browser_ &&
+ !browser_->tabstrip_model()->closing_all() && GetWindow()->IsVisible()) {
+ // We only restore focus if our window is visible, to avoid invoking blur
+ // handlers when we are eventually shown.
+ new_contents->view()->RestoreFocus();
+ }
+
+ // Update all the UI bits.
+ UpdateTitleBar();
+ UpdateToolbar(new_contents, true);
+ UpdateUIForContents(new_contents);
+}
+
#if !defined(OS_CHROMEOS)
// static
BrowserWindow* BrowserWindow::CreateBrowserWindow(Browser* browser) {
diff --git a/chrome/browser/views/frame/browser_view.h b/chrome/browser/views/frame/browser_view.h
index 37657f0..d2cadda 100644
--- a/chrome/browser/views/frame/browser_view.h
+++ b/chrome/browser/views/frame/browser_view.h
@@ -24,6 +24,7 @@
#include "chrome/browser/views/tabs/tab_strip.h"
#include "chrome/browser/views/tabs/base_tab_strip.h"
#include "chrome/browser/views/unhandled_keyboard_event_handler.h"
+#include "chrome/common/notification_registrar.h"
#include "gfx/native_widget_types.h"
#include "views/window/client_view.h"
#include "views/window/window_delegate.h"
@@ -335,6 +336,10 @@ class BrowserView : public BrowserBubbleHost,
TabContents* new_contents,
int index,
bool user_gesture);
+ virtual void TabReplacedAt(TabContents* old_contents,
+ TabContents* new_contents,
+ int index,
+ TabStripModelObserver::TabReplaceType type);
virtual void TabStripEmpty();
// Overridden from menus::SimpleMenuModel::Delegate:
@@ -412,6 +417,8 @@ class BrowserView : public BrowserBubbleHost,
private:
friend class BrowserViewLayout;
+ class ContentsContainer;
+
#if defined(OS_WIN)
// Creates the system menu.
void InitSystemMenu();
@@ -477,8 +484,17 @@ class BrowserView : public BrowserBubbleHost,
// Initialize the hung plugin detector.
void InitHangMonitor();
- // Initialize class statics.
- static void InitClass();
+ // Shows the match preview for the selected tab contents.
+ void ShowMatchPreview();
+
+ // Hides the match preview for the selected tab contents.
+ void HideMatchPreview();
+
+ // Invoked from TabSelectedAt or when the match preview is made active. Is
+ // |change_tab_contents| is true, |new_contents| is added to the view
+ // hierarchy, if |change_tab_contents| is false, it's assumed |new_contents|
+ // has already been added to the view hierarchy.
+ void ProcessTabSelected(TabContents* new_contents, bool change_tab_contents);
// Last focused view that issued a tab traversal.
int last_focused_view_storage_id_;
@@ -515,6 +531,12 @@ class BrowserView : public BrowserBubbleHost,
// The view that contains devtools window for the selected TabContents.
TabContentsContainer* devtools_container_;
+ // The view that contains the match preview TabContents.
+ TabContentsContainer* preview_container_;
+
+ // The view managing both the contents_container_ and preview_container_.
+ ContentsContainer* contents_;
+
// Split view containing the contents container and devtools container.
views::SingleSplitView* contents_split_;
@@ -576,6 +598,8 @@ class BrowserView : public BrowserBubbleHost,
scoped_ptr<AccessibleViewHelper> accessible_view_helper_;
+ NotificationRegistrar registrar_;
+
DISALLOW_COPY_AND_ASSIGN(BrowserView);
};
diff --git a/chrome/browser/views/location_bar/location_bar_view.cc b/chrome/browser/views/location_bar/location_bar_view.cc
index f42d9af..e8d8e05 100644
--- a/chrome/browser/views/location_bar/location_bar_view.cc
+++ b/chrome/browser/views/location_bar/location_bar_view.cc
@@ -19,6 +19,7 @@
#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/search_engines/template_url_model.h"
+#include "chrome/browser/tab_contents/match_preview.h"
#include "chrome/browser/view_ids.h"
#include "chrome/browser/views/browser_dialogs.h"
#include "chrome/browser/views/location_bar/content_setting_image_view.h"
@@ -712,6 +713,13 @@ void LocationBarView::OnChanged() {
location_entry_->GetIcon()));
Layout();
SchedulePaint();
+
+ if (MatchPreview::IsEnabled() && GetTabContents() &&
+ !profile_->IsOffTheRecord()) {
+ GURL url = location_entry_->model()->user_input_in_progress() ?
+ location_entry_->model()->CurrentURL() : GURL();
+ GetTabContents()->match_preview()->Update(url);
+ }
}
void LocationBarView::OnInputInProgress(bool in_progress) {
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 375120e..7e9d7fe 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -2484,6 +2484,8 @@
'browser/tab_contents/interstitial_page.h',
'browser/tab_contents/language_state.h',
'browser/tab_contents/language_state.cc',
+ 'browser/tab_contents/match_preview.cc',
+ 'browser/tab_contents/match_preview.h',
'browser/tab_contents/navigation_controller.cc',
'browser/tab_contents/navigation_controller.h',
'browser/tab_contents/navigation_entry.cc',
@@ -2514,8 +2516,8 @@
'browser/tab_contents/tab_contents_view_gtk.h',
'browser/tab_contents/tab_contents_view_mac.h',
'browser/tab_contents/tab_contents_view_mac.mm',
- 'browser/tab_contents/tab_specific_content_settings.h',
'browser/tab_contents/tab_specific_content_settings.cc',
+ 'browser/tab_contents/tab_specific_content_settings.h',
'browser/tab_contents/tab_util.cc',
'browser/tab_contents/tab_util.h',
'browser/tab_contents/thumbnail_generator.cc',
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index 27e5cf4..34b8be9 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -376,6 +376,9 @@ const char kEnableGPURendering[] = "enable-gpu-rendering";
// builds.
const char kEnableLogging[] = "enable-logging";
+// Is match preview enabled?
+const char kEnableMatchPreview[] = "enable-match-preview";
+
// Allows reporting memory info (JS heap size) to page.
const char kEnableMemoryInfo[] = "enable-memory-info";
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index 362a3a6..fbc8b81 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -122,6 +122,7 @@ extern const char kEnableIndexedDatabase[];
extern const char kEnableInMemoryURLIndex[];
extern const char kEnableIPv6[];
extern const char kEnableLogging[];
+extern const char kEnableMatchPreview[];
extern const char kEnableMemoryInfo[];
extern const char kEnableMonitorProfile[];
extern const char kEnableNaCl[];
diff --git a/chrome/common/notification_type.h b/chrome/common/notification_type.h
index ed8b2b2..7c19c9e 100644
--- a/chrome/common/notification_type.h
+++ b/chrome/common/notification_type.h
@@ -393,6 +393,10 @@ class NotificationType {
// pointer.
RENDER_VIEW_HOST_CREATED_FOR_TAB,
+ // Sent when MatchPreview creates the preview TabContents. The source is the
+ // TabContents the MatchPreview is associated with.
+ MATCH_PREVIEW_TAB_CONTENTS_CREATED,
+
// Stuff inside the tabs ---------------------------------------------------
// This message is sent after a constrained window has been closed. The