summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
authorerg@google.com <erg@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-04 19:22:13 +0000
committererg@google.com <erg@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-04 19:22:13 +0000
commit66ba493b842d92a7d9e515302d585d1c56848ee0 (patch)
tree59f303d8f54c0447268302fdabce7c873fe2c09b /chrome/browser
parent33b28a75192e79cff41ecbe82defd65ad5da9535 (diff)
downloadchromium_src-66ba493b842d92a7d9e515302d585d1c56848ee0.zip
chromium_src-66ba493b842d92a7d9e515302d585d1c56848ee0.tar.gz
chromium_src-66ba493b842d92a7d9e515302d585d1c56848ee0.tar.bz2
Relanding the first of probably several patches trying to clean up the BlockedPopupContainer into something that can be cross-platform.
- BlokedPopupContainers are no longer ConstrainedWindows. - There is now a cross platform base class that contains most of the model/controller logic. The view now inherits from it. This is an improvement. This version has minor windows compile fixes that changed from under me. Original Review URL: http://codereview.chromium.org/119006 TBR=beng TEST=Popup notification still works. Review URL: http://codereview.chromium.org/119107 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@17647 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rwxr-xr-x[-rw-r--r--]chrome/browser/automation/automation_provider.cc21
-rw-r--r--chrome/browser/automation/automation_provider.h3
-rw-r--r--chrome/browser/blocked_popup_container.cc337
-rw-r--r--chrome/browser/blocked_popup_container.h258
-rw-r--r--chrome/browser/browser.vcproj8
-rw-r--r--chrome/browser/tab_contents/tab_contents.cc50
-rw-r--r--chrome/browser/tab_contents/tab_contents.h12
-rw-r--r--chrome/browser/tab_contents/tab_contents_view_win.cc2
-rw-r--r--chrome/browser/views/blocked_popup_container.cc433
-rw-r--r--chrome/browser/views/blocked_popup_container.h216
-rw-r--r--chrome/browser/views/constrained_window_impl_interactive_uitest.cc30
11 files changed, 753 insertions, 617 deletions
diff --git a/chrome/browser/automation/automation_provider.cc b/chrome/browser/automation/automation_provider.cc
index 7fce063..e61882d 100644..100755
--- a/chrome/browser/automation/automation_provider.cc
+++ b/chrome/browser/automation/automation_provider.cc
@@ -21,6 +21,7 @@
#include "chrome/browser/automation/url_request_failed_dns_job.h"
#include "chrome/browser/automation/url_request_mock_http_job.h"
#include "chrome/browser/automation/url_request_slow_download_job.h"
+#include "chrome/browser/blocked_popup_container.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/dom_operation_notification_details.h"
#include "chrome/browser/download/download_manager.h"
@@ -1084,6 +1085,7 @@ void AutomationProvider::OnMessageReceived(const IPC::Message& message) {
IPC_MESSAGE_HANDLER(AutomationMsg_SetEnableExtensionAutomation,
SetEnableExtensionAutomation)
IPC_MESSAGE_HANDLER(AutomationMsg_SetShelfVisibility, SetShelfVisibility)
+ IPC_MESSAGE_HANDLER(AutomationMsg_BlockedPopupCount, GetBlockedPopupCount)
IPC_END_MESSAGE_MAP()
}
@@ -3004,3 +3006,22 @@ void AutomationProvider::GetWindowTitle(int handle, string16* text) {
gfx::NativeWindow window = window_tracker_->GetResource(handle);
text->assign(platform_util::GetWindowTitle(window));
}
+
+void AutomationProvider::GetBlockedPopupCount(int handle, int* count) {
+ *count = -1; // -1 is the error code
+ if (tab_tracker_->ContainsHandle(handle)) {
+ NavigationController* nav_controller = tab_tracker_->GetResource(handle);
+ TabContents* tab_contents = nav_controller->tab_contents();
+ if (tab_contents) {
+ BlockedPopupContainer* container =
+ tab_contents->blocked_popup_container();
+ if (container) {
+ *count = static_cast<int>(container->GetBlockedPopupCount());
+ } else {
+ // If we don't have a container, we don't have any blocked popups to
+ // contain!
+ *count = 0;
+ }
+ }
+ }
+}
diff --git a/chrome/browser/automation/automation_provider.h b/chrome/browser/automation/automation_provider.h
index 8673bed..04a6bd8 100644
--- a/chrome/browser/automation/automation_provider.h
+++ b/chrome/browser/automation/automation_provider.h
@@ -452,6 +452,9 @@ class AutomationProvider : public base::RefCounted<AutomationProvider>,
void GetWindowTitle(int handle, string16* text);
+ // Returns the number of blocked popups in the tab |handle|.
+ void GetBlockedPopupCount(int handle, int* count);
+
// Convert a tab handle into a TabContents. If |tab| is non-NULL a pointer
// to the tab is also returned. Returns NULL in case of failure or if the tab
// is not of the TabContents type.
diff --git a/chrome/browser/blocked_popup_container.cc b/chrome/browser/blocked_popup_container.cc
new file mode 100644
index 0000000..ad9c7c6
--- /dev/null
+++ b/chrome/browser/blocked_popup_container.cc
@@ -0,0 +1,337 @@
+// Copyright (c) 2009 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/blocked_popup_container.h"
+
+#include "chrome/browser/extensions/extension_function_dispatcher.h"
+#include "chrome/browser/profile.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/common/pref_service.h"
+#include "chrome/common/notification_service.h"
+
+// static
+void BlockedPopupContainer::RegisterUserPrefs(PrefService* prefs) {
+ prefs->RegisterListPref(prefs::kPopupWhitelistedHosts);
+}
+
+void BlockedPopupContainer::AddTabContents(TabContents* tab_contents,
+ const gfx::Rect& bounds,
+ const std::string& host) {
+ // Show whitelisted popups immediately.
+ bool whitelisted = !!whitelist_.count(host);
+ if (whitelisted)
+ owner_->AddNewContents(tab_contents, NEW_POPUP, bounds, true, GURL());
+
+ if (has_been_dismissed_) {
+ // Don't want to show any other UI.
+ if (!whitelisted)
+ delete tab_contents; // Discard blocked popups entirely.
+ return;
+ }
+
+ if (whitelisted) {
+ // Listen for this popup's destruction, so if the user closes it manually,
+ // we'll know to stop caring about it.
+ registrar_.Add(this, NotificationType::TAB_CONTENTS_DESTROYED,
+ Source<TabContents>(tab_contents));
+
+ unblocked_popups_[tab_contents] = host;
+ } else {
+ if (blocked_popups_.size() >= kImpossibleNumberOfPopups) {
+ delete tab_contents;
+ LOG(INFO) << "Warning: Renderer is sending more popups to us than should "
+ "be possible. Renderer compromised?";
+ return;
+ }
+ blocked_popups_.push_back(BlockedPopup(tab_contents, bounds, host));
+
+ tab_contents->set_delegate(this);
+ }
+
+ PopupHosts::const_iterator i(popup_hosts_.find(host));
+ if (i == popup_hosts_.end())
+ popup_hosts_[host] = whitelisted;
+ else
+ DCHECK_EQ(whitelisted, i->second);
+
+ // Update UI.
+ UpdateLabel();
+ ShowSelf();
+ owner_->PopupNotificationVisibilityChanged(true);
+}
+
+void BlockedPopupContainer::LaunchPopupAtIndex(size_t index) {
+ if (index >= blocked_popups_.size())
+ return;
+
+ // Open the popup.
+ BlockedPopups::iterator i(blocked_popups_.begin() + index);
+ TabContents* tab_contents = i->tab_contents;
+ tab_contents->set_delegate(NULL);
+ owner_->AddNewContents(tab_contents, NEW_POPUP, i->bounds, true, GURL());
+
+ const std::string& host = i->host;
+ if (!host.empty()) {
+ // Listen for this popup's destruction, so if the user closes it manually,
+ // we'll know to stop caring about it.
+ registrar_.Add(this, NotificationType::TAB_CONTENTS_DESTROYED,
+ Source<TabContents>(tab_contents));
+
+ // Add the popup to the unblocked list. (Do this before the below call!)
+ unblocked_popups_[tab_contents] = i->host;
+ }
+
+ // Remove the popup from the blocked list.
+ EraseDataForPopupAndUpdateUI(i);
+}
+
+size_t BlockedPopupContainer::GetBlockedPopupCount() const {
+ return blocked_popups_.size();
+}
+
+bool BlockedPopupContainer::IsHostWhitelisted(size_t index) const {
+ PopupHosts::const_iterator i(ConvertHostIndexToIterator(index));
+ return (i == popup_hosts_.end()) ? false : i->second;
+}
+
+void BlockedPopupContainer::ToggleWhitelistingForHost(size_t index) {
+ PopupHosts::const_iterator i(ConvertHostIndexToIterator(index));
+ const std::string& host = i->first;
+ bool should_whitelist = !i->second;
+ popup_hosts_[host] = should_whitelist;
+
+ ListValue* whitelist_pref =
+ prefs_->GetMutableList(prefs::kPopupWhitelistedHosts);
+ if (should_whitelist) {
+ whitelist_.insert(host);
+ whitelist_pref->Append(new StringValue(host));
+
+ // Open the popups in order.
+ for (size_t j = 0; j < blocked_popups_.size(); ) {
+ if (blocked_popups_[j].host == host)
+ LaunchPopupAtIndex(j); // This shifts the rest of the entries down.
+ else
+ ++j;
+ }
+ } else {
+ // Remove from whitelist.
+ whitelist_.erase(host);
+ StringValue host_as_string(host);
+ whitelist_pref->Remove(host_as_string);
+
+ for (UnblockedPopups::iterator i(unblocked_popups_.begin());
+ i != unblocked_popups_.end(); ) {
+ TabContents* tab_contents = i->first;
+ TabContentsDelegate* delegate = tab_contents->delegate();
+ if ((i->second == host) && delegate->IsPopup(tab_contents)) {
+ // Convert the popup back into a blocked popup.
+ delegate->DetachContents(tab_contents);
+ tab_contents->set_delegate(this);
+
+ // Add the popup to the blocked list. (Do this before the below call!)
+ gfx::Rect bounds;
+ tab_contents->GetContainerBounds(&bounds);
+ blocked_popups_.push_back(BlockedPopup(tab_contents, bounds, host));
+
+ // Remove the popup from the unblocked list.
+ UnblockedPopups::iterator to_erase = i;
+ ++i;
+ EraseDataForPopupAndUpdateUI(to_erase);
+ } else {
+ ++i;
+ }
+ }
+ }
+}
+
+void BlockedPopupContainer::CloseAll() {
+ ClearData();
+ HideSelf();
+}
+
+// Overridden from TabContentsDelegate:
+void BlockedPopupContainer::OpenURLFromTab(TabContents* source,
+ const GURL& url,
+ const GURL& referrer,
+ WindowOpenDisposition disposition,
+ PageTransition::Type transition) {
+ owner_->OpenURL(url, referrer, disposition, transition);
+}
+
+void BlockedPopupContainer::AddNewContents(TabContents* source,
+ TabContents* new_contents,
+ WindowOpenDisposition disposition,
+ const gfx::Rect& initial_position,
+ bool user_gesture) {
+ owner_->AddNewContents(new_contents, disposition, initial_position,
+ user_gesture, GURL());
+}
+
+void BlockedPopupContainer::CloseContents(TabContents* source) {
+ for (BlockedPopups::iterator it = blocked_popups_.begin();
+ it != blocked_popups_.end(); ++it) {
+ TabContents* tab_contents = it->tab_contents;
+ if (tab_contents == source) {
+ tab_contents->set_delegate(NULL);
+ EraseDataForPopupAndUpdateUI(it);
+ delete tab_contents;
+ break;
+ }
+ }
+}
+
+void BlockedPopupContainer::MoveContents(TabContents* source,
+ const gfx::Rect& new_bounds) {
+ for (BlockedPopups::iterator it = blocked_popups_.begin();
+ it != blocked_popups_.end(); ++it) {
+ if (it->tab_contents == source) {
+ it->bounds = new_bounds;
+ break;
+ }
+ }
+}
+
+bool BlockedPopupContainer::IsPopup(TabContents* source) {
+ return true;
+}
+
+TabContents* BlockedPopupContainer::GetConstrainingContents(
+ TabContents* source) {
+ return owner_;
+}
+
+ExtensionFunctionDispatcher* BlockedPopupContainer::
+ CreateExtensionFunctionDispatcher(RenderViewHost* render_view_host,
+ const std::string& extension_id) {
+ return new ExtensionFunctionDispatcher(render_view_host, NULL, extension_id);
+}
+
+void BlockedPopupContainer::HideSelf() {
+ owner_->PopupNotificationVisibilityChanged(false);
+}
+
+void BlockedPopupContainer::ClearData() {
+ for (BlockedPopups::iterator i(blocked_popups_.begin());
+ i != blocked_popups_.end(); ++i) {
+ TabContents* tab_contents = i->tab_contents;
+ tab_contents->set_delegate(NULL);
+ delete tab_contents;
+ }
+ blocked_popups_.clear();
+
+ registrar_.RemoveAll();
+ unblocked_popups_.clear();
+
+ popup_hosts_.clear();
+}
+
+BlockedPopupContainer::PopupHosts::const_iterator
+ BlockedPopupContainer::ConvertHostIndexToIterator(size_t index) const {
+ if (index >= popup_hosts_.size())
+ return popup_hosts_.end();
+ // If only there was a std::map::const_iterator::operator +=() ...
+ PopupHosts::const_iterator i(popup_hosts_.begin());
+ for (size_t j = 0; j < index; ++j)
+ ++i;
+ return i;
+}
+
+void BlockedPopupContainer::EraseDataForPopupAndUpdateUI(
+ BlockedPopups::iterator i) {
+ // Erase the host if this is the last popup for that host.
+ const std::string& host = i->host;
+ if (!host.empty()) {
+ bool should_erase_host = true;
+ for (BlockedPopups::const_iterator j(blocked_popups_.begin());
+ j != blocked_popups_.end(); ++j) {
+ if ((j != i) && (j->host == host)) {
+ should_erase_host = false;
+ break;
+ }
+ }
+ if (should_erase_host) {
+ for (UnblockedPopups::const_iterator j(unblocked_popups_.begin());
+ j != unblocked_popups_.end(); ++j) {
+ if (j->second == host) {
+ should_erase_host = false;
+ break;
+ }
+ }
+ if (should_erase_host)
+ popup_hosts_.erase(host);
+ }
+ }
+
+ // Erase the popup and update the UI.
+ blocked_popups_.erase(i);
+ UpdateLabel();
+}
+
+void BlockedPopupContainer::EraseDataForPopupAndUpdateUI(
+ UnblockedPopups::iterator i) {
+ // Stop listening for this popup's destruction.
+ registrar_.Remove(this, NotificationType::TAB_CONTENTS_DESTROYED,
+ Source<TabContents>(i->first));
+
+ // Erase the host if this is the last popup for that host.
+ const std::string& host = i->second;
+ if (!host.empty()) {
+ bool should_erase_host = true;
+ for (UnblockedPopups::const_iterator j(unblocked_popups_.begin());
+ j != unblocked_popups_.end(); ++j) {
+ if ((j != i) && (j->second == host)) {
+ should_erase_host = false;
+ break;
+ }
+ }
+ if (should_erase_host) {
+ for (BlockedPopups::const_iterator j(blocked_popups_.begin());
+ j != blocked_popups_.end(); ++j) {
+ if (j->host == host) {
+ should_erase_host = false;
+ break;
+ }
+ }
+ if (should_erase_host)
+ popup_hosts_.erase(host);
+ }
+ }
+
+ // Erase the popup and update the UI.
+ unblocked_popups_.erase(i);
+ UpdateLabel();
+}
+
+
+// private:
+
+BlockedPopupContainer::BlockedPopupContainer(TabContents* owner,
+ PrefService* prefs)
+ : owner_(owner),
+ prefs_(prefs),
+ has_been_dismissed_(false) {
+ // Copy whitelist pref into local member that's easier to use.
+ const ListValue* whitelist_pref =
+ prefs_->GetList(prefs::kPopupWhitelistedHosts);
+ // Careful: The returned value could be NULL if the pref has never been set.
+ if (whitelist_pref != NULL) {
+ for (ListValue::const_iterator i(whitelist_pref->begin());
+ i != whitelist_pref->end(); ++i) {
+ std::string host;
+ (*i)->GetAsString(&host);
+ whitelist_.insert(host);
+ }
+ }
+}
+
+void BlockedPopupContainer::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ DCHECK(type == NotificationType::TAB_CONTENTS_DESTROYED);
+ TabContents* tab_contents = Source<TabContents>(source).ptr();
+ UnblockedPopups::iterator i(unblocked_popups_.find(tab_contents));
+ DCHECK(i != unblocked_popups_.end());
+ EraseDataForPopupAndUpdateUI(i);
+}
diff --git a/chrome/browser/blocked_popup_container.h b/chrome/browser/blocked_popup_container.h
new file mode 100644
index 0000000..f9b5d14
--- /dev/null
+++ b/chrome/browser/blocked_popup_container.h
@@ -0,0 +1,258 @@
+// Copyright (c) 2009 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.
+
+// Defines the public interface for the blocked popup notifications. This
+// interface should only be used by TabContents. Users and subclasses of
+// TabContents should use the appropriate methods on TabContents to access
+// information about blocked popups.
+
+#ifndef CHROME_BROWSER_BLOCKED_POPUP_CONTAINER_H_
+#define CHROME_BROWSER_BLOCKED_POPUP_CONTAINER_H_
+
+#include <map>
+#include <set>
+
+#include "base/gfx/native_widget_types.h"
+#include "base/gfx/rect.h"
+#include "chrome/browser/tab_contents/constrained_window.h"
+#include "chrome/browser/tab_contents/tab_contents_delegate.h"
+#include "chrome/common/notification_registrar.h"
+
+class BlockedPopupContainerImpl;
+class PrefService;
+class Profile;
+class TabContents;
+
+// Takes ownership of TabContents that are unrequested popup windows and
+// presents an interface to the user for launching them. (Or never showing them
+// again). This class contains all the cross-platform bits that can be used in
+// all ports.
+//
+// Currently, BlockedPopupContainer only exists as a cross platform model
+// extracted from browser/views/blocked_popup_container.cc. This is what it
+// used to look like before:
+//
+// +- BlockedPopupContainer -------------------------------+
+// | <views::WidgetWin> |
+// | All model logic. |
+// | All views code. |
+// +-------------------------------------------------------+
+//
+// As of now, it looks like this:
+//
+// +- BlockedPopupContainer -------------------------------+
+// | All model logic |
+// +-------------------------------------------------------+
+// ^
+// |
+// +- BlockedPopupContainerImpl ---------------------------+
+// | views::WidgetWin |
+// | All views code. |
+// | |
+// +-------------------------------------------------------+
+//
+// TODO(erg): While it is not in this state yet, I want it to look like this:
+//
+// +- BlockedPopupContainer ---+ +- BlockedPopupContainerView -----+
+// | All model logic | +--->| Abstract cross platform |
+// | | | | interface |
+// | | | | |
+// | Owns a platform view_ +----+ | |
+// +---------------------------+ +---------------------------------+
+// ^
+// |
+// +-------------------------------+-----------+
+// | |
+// +- BPCViewGtk -----------+ +- BPCViewWin ----------------------+
+// | Gtk UI | | Views UI |
+// | | | |
+// +------------------------+ +-----------------------------------+
+//
+// Getting here will take multiple patches.
+class BlockedPopupContainer : public TabContentsDelegate,
+ public NotificationObserver {
+ public:
+ // Creates a BlockedPopupContainer, anchoring the container to the lower
+ // right corner.
+ static BlockedPopupContainer* Create(
+ TabContents* owner, Profile* profile, const gfx::Point& initial_anchor);
+
+ static void RegisterUserPrefs(PrefService* prefs);
+
+ // Adds a popup to this container. |bounds| are the window bounds requested by
+ // the popup window.
+ void AddTabContents(TabContents* tab_contents,
+ const gfx::Rect& bounds,
+ const std::string& host);
+
+ // Shows the blocked popup at index |index|.
+ void LaunchPopupAtIndex(size_t index);
+
+ // Returns the number of blocked popups
+ size_t GetBlockedPopupCount() const;
+
+ // Returns true if host |index| is whitelisted. Returns false if |index| is
+ // invalid.
+ bool IsHostWhitelisted(size_t index) const;
+
+ // If host |index| is currently whitelisted, un-whitelists it. Otherwise,
+ // whitelists it and opens all blocked popups from it.
+ void ToggleWhitelistingForHost(size_t index);
+
+ // Deletes all popups and hides the interface parts.
+ void CloseAll();
+
+ // Sets this object up to delete itself.
+ virtual void Destroy() = 0;
+
+ // Message called when a BlockedPopupContainer should move itself to the
+ // bottom right corner of |view|.
+ virtual void RepositionBlockedPopupContainer(gfx::NativeView view) = 0;
+
+ // Called to force this container to never show itself again.
+ void set_dismissed() { has_been_dismissed_ = true; }
+
+ // Overridden from TabContentsDelegate:
+
+ // Forwards OpenURLFromTab to our |owner_|.
+ virtual void OpenURLFromTab(TabContents* source,
+ const GURL& url, const GURL& referrer,
+ WindowOpenDisposition disposition,
+ PageTransition::Type transition);
+
+ // Ignored; BlockedPopupContainer doesn't display a throbber.
+ virtual void NavigationStateChanged(const TabContents* source,
+ unsigned changed_flags) { }
+
+ // Forwards AddNewContents to our |owner_|.
+ virtual void AddNewContents(TabContents* source,
+ TabContents* new_contents,
+ WindowOpenDisposition disposition,
+ const gfx::Rect& initial_position,
+ bool user_gesture);
+
+ // Ignore activation requests from the TabContents we're blocking.
+ virtual void ActivateContents(TabContents* contents) { }
+
+ // Ignored; BlockedPopupContainer doesn't display a throbber.
+ virtual void LoadingStateChanged(TabContents* source) { }
+
+ // Removes |source| from our internal list of blocked popups.
+ virtual void CloseContents(TabContents* source);
+
+ // Changes the opening rectangle associated with |source|.
+ virtual void MoveContents(TabContents* source, const gfx::Rect& new_bounds);
+
+ // Always returns true.
+ virtual bool IsPopup(TabContents* source);
+
+ // Returns our |owner_|.
+ virtual TabContents* GetConstrainingContents(TabContents* source);
+
+ // Ignored; BlockedPopupContainer doesn't display a toolbar.
+ virtual void ToolbarSizeChanged(TabContents* source, bool is_animating) { }
+
+ // Ignored; BlockedPopupContainer doesn't display a bookmarking star.
+ virtual void URLStarredChanged(TabContents* source, bool starred) { }
+
+ // Ignored; BlockedPopupContainer doesn't display a URL bar.
+ virtual void UpdateTargetURL(TabContents* source, const GURL& url) { }
+
+ // Creates an ExtensionFunctionDispatcher that has no browser
+ virtual ExtensionFunctionDispatcher* CreateExtensionFunctionDispatcher(
+ RenderViewHost* render_view_host,
+ const std::string& extension_id);
+
+ // A number larger than the internal popup count on the Renderer; meant for
+ // preventing a compromised renderer from exhausting GDI memory by spawning
+ // infinite windows.
+ static const size_t kImpossibleNumberOfPopups = 30;
+
+ protected:
+ struct BlockedPopup {
+ BlockedPopup(TabContents* tab_contents,
+ const gfx::Rect& bounds,
+ const std::string& host)
+ : tab_contents(tab_contents), bounds(bounds), host(host) {
+ }
+
+ TabContents* tab_contents;
+ gfx::Rect bounds;
+ std::string host;
+ };
+ typedef std::vector<BlockedPopup> BlockedPopups;
+
+ // TabContents is the popup contents. string is opener hostname.
+ typedef std::map<TabContents*, std::string> UnblockedPopups;
+
+ // string is hostname. bool is whitelisted status.
+ typedef std::map<std::string, bool> PopupHosts;
+
+ // Shows the UI.
+ virtual void ShowSelf() = 0;
+
+ // Hides the UI portion of the container.
+ virtual void HideSelf();
+
+ // Updates the text on the label on the notification.
+ virtual void UpdateLabel() = 0;
+
+ // Deletes all local state.
+ virtual void ClearData();
+
+ // Helper function to convert a host index (which the view uses) into an
+ // iterator into |popup_hosts_|. Returns popup_hosts_.end() if |index| is
+ // invalid.
+ PopupHosts::const_iterator ConvertHostIndexToIterator(size_t index) const;
+
+ // Removes the popup at |i| from the blocked popup list. If this popup's host
+ // is not otherwised referenced on either popup list, removes the host from
+ // the host list. Updates the view's label to match the new state.
+ void EraseDataForPopupAndUpdateUI(BlockedPopups::iterator i);
+
+ // Same as above, but works on the unblocked popup list.
+ void EraseDataForPopupAndUpdateUI(UnblockedPopups::iterator i);
+
+ private:
+ friend class BlockedPopupContainerImpl;
+
+ // string is hostname.
+ typedef std::set<std::string> Whitelist;
+
+ // Creates a container for a certain TabContents:
+ BlockedPopupContainer(TabContents* owner, PrefService* prefs);
+
+ // Overridden from notificationObserver:
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ // The TabContents that owns and constrains this BlockedPopupContainer.
+ TabContents* owner_;
+
+ // The PrefService we can query to find out what's on the whitelist.
+ PrefService* prefs_;
+
+ // Once the container is hidden, this is set to prevent it from reappearing.
+ bool has_been_dismissed_;
+
+ // Registrar to handle notifications we care about.
+ NotificationRegistrar registrar_;
+
+ // The whitelisted hosts, which we allow to open popups directly.
+ Whitelist whitelist_;
+
+ // Information about all blocked popups.
+ BlockedPopups blocked_popups_;
+
+ // Information about all unblocked popups.
+ UnblockedPopups unblocked_popups_;
+
+ // Information about all popup hosts.
+ PopupHosts popup_hosts_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(BlockedPopupContainer);
+};
+
+#endif // CHROME_BROWSER_BLOCKED_POPUP_CONTAINER_H_
diff --git a/chrome/browser/browser.vcproj b/chrome/browser/browser.vcproj
index 9407918..1d1b3b6 100644
--- a/chrome/browser/browser.vcproj
+++ b/chrome/browser/browser.vcproj
@@ -2689,6 +2689,14 @@
</File>
</Filter>
<File
+ RelativePath=".\blocked_popup_container.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\blocked_popup_container.h"
+ >
+ </File>
+ <File
RelativePath=".\browser_trial.cc"
>
</File>
diff --git a/chrome/browser/tab_contents/tab_contents.cc b/chrome/browser/tab_contents/tab_contents.cc
index 4bc4366..59034a5 100644
--- a/chrome/browser/tab_contents/tab_contents.cc
+++ b/chrome/browser/tab_contents/tab_contents.cc
@@ -11,6 +11,7 @@
#include "base/string16.h"
#include "base/time.h"
#include "chrome/browser/autofill_manager.h"
+#include "chrome/browser/blocked_popup_container.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/cert_store.h"
@@ -53,9 +54,10 @@
#include "net/base/registry_controlled_domain.h"
#if defined(OS_WIN)
+// For CRect
+#include <atlmisc.h>
// TODO(port): some of these headers should be ported.
#include "chrome/browser/modal_html_dialog_delegate.h"
-#include "chrome/browser/views/blocked_popup_container.h"
#include "views/controls/scrollbar/native_scroll_bar.h"
#endif
@@ -200,14 +202,16 @@ TabContents::TabContents(Profile* profile,
int routing_id,
base::WaitableEvent* modal_dialog_event)
: delegate_(NULL),
- controller_(this, profile),
- view_(TabContentsView::Create(static_cast<TabContents*>(this))),
+ ALLOW_THIS_IN_INITIALIZER_LIST(controller_(this, profile)),
+ ALLOW_THIS_IN_INITIALIZER_LIST(view_(
+ TabContentsView::Create(static_cast<TabContents*>(this)))),
ALLOW_THIS_IN_INITIALIZER_LIST(render_manager_(
static_cast<TabContents*>(this),
static_cast<TabContents*>(this))),
property_bag_(),
registrar_(),
- printing_(*static_cast<TabContents*>(this)),
+ ALLOW_THIS_IN_INITIALIZER_LIST(printing_(
+ *static_cast<TabContents*>(this))),
save_package_(),
cancelable_consumer_(),
autofill_manager_(),
@@ -306,6 +310,9 @@ TabContents::~TabContents() {
window->CloseConstrainedWindow();
}
+ if (blocked_popups_)
+ blocked_popups_->Destroy();
+
// Notify any observer that have a reference on this tab contents.
NotificationService::current()->Notify(
NotificationType::TAB_CONTENTS_DESTROYED,
@@ -815,12 +822,10 @@ void TabContents::AddNewContents(TabContents* new_contents,
#endif
}
-#if defined(OS_WIN)
void TabContents::CloseAllSuppressedPopups() {
if (blocked_popups_)
blocked_popups_->CloseAll();
}
-#endif
void TabContents::PopupNotificationVisibilityChanged(bool visible) {
render_view_host()->PopupNotificationVisibilityChanged(visible);
@@ -937,18 +942,12 @@ void TabContents::WillClose(ConstrainedWindow* window) {
find(child_windows_.begin(), child_windows_.end(), window);
if (it != child_windows_.end())
child_windows_.erase(it);
+}
-#if defined(OS_WIN)
- if (window == blocked_popups_)
- blocked_popups_ = NULL;
-
- if (::IsWindow(GetNativeView())) {
- CRect client_rect;
- GetClientRect(GetNativeView(), &client_rect);
- RepositionSupressedPopupsToFit(
- gfx::Size(client_rect.Width(), client_rect.Height()));
- }
-#endif
+void TabContents::WillCloseBlockedPopupContainer(
+ BlockedPopupContainer* container) {
+ DCHECK(blocked_popups_ == container);
+ blocked_popups_ = NULL;
}
void TabContents::DidMoveOrResize(ConstrainedWindow* window) {
@@ -1112,7 +1111,6 @@ void TabContents::CreateBlockedPopupContainerIfNecessary() {
client_rect.Height());
blocked_popups_ = BlockedPopupContainer::Create(this, profile(),
anchor_position);
- child_windows_.push_back(blocked_popups_);
}
void TabContents::AddPopup(TabContents* new_contents,
@@ -1121,28 +1119,18 @@ void TabContents::AddPopup(TabContents* new_contents,
CreateBlockedPopupContainerIfNecessary();
blocked_popups_->AddTabContents(new_contents, initial_pos, host);
}
+#endif
// TODO(brettw) This should be on the TabContentsView.
-void TabContents::RepositionSupressedPopupsToFit(const gfx::Size& new_size) {
- // TODO(erg): There's no way to detect whether scroll bars are
- // visible, so for beta, we're just going to assume that the
- // vertical scroll bar is visible, and not care about covering up
- // the horizontal scroll bar. Fixing this is half of
- // http://b/1118139.
- gfx::Point anchor_position(
- new_size.width() -
- views::NativeScrollBar::GetVerticalScrollBarWidth(),
- new_size.height());
-
+void TabContents::RepositionSupressedPopupsToFit() {
if (blocked_popups_)
- blocked_popups_->RepositionConstrainedWindowTo(anchor_position);
+ blocked_popups_->RepositionBlockedPopupContainer(GetNativeView());
}
bool TabContents::ShowingBlockedPopupNotification() const {
return blocked_popups_ != NULL &&
blocked_popups_->GetBlockedPopupCount() != 0;
}
-#endif // defined(OS_WIN)
namespace {
bool TransitionIsReload(PageTransition::Type transition) {
diff --git a/chrome/browser/tab_contents/tab_contents.h b/chrome/browser/tab_contents/tab_contents.h
index 026cf3d..2853ceb 100644
--- a/chrome/browser/tab_contents/tab_contents.h
+++ b/chrome/browser/tab_contents/tab_contents.h
@@ -413,6 +413,9 @@ class TabContents : public PageNavigator,
// Called when a ConstrainedWindow we own is about to be closed.
void WillClose(ConstrainedWindow* window);
+ // Called when a BlockedPopupContainer we own is about to be closed.
+ void WillCloseBlockedPopupContainer(BlockedPopupContainer* container);
+
// Called when a ConstrainedWindow we own is moved or resized.
void DidMoveOrResize(ConstrainedWindow* window);
@@ -555,6 +558,10 @@ class TabContents : public PageNavigator,
render_view_host()->WindowMoveOrResizeStarted();
}
+ BlockedPopupContainer* blocked_popup_container() const {
+ return blocked_popups_;
+ }
+
private:
friend class NavigationController;
// Used to access the child_windows_ (ConstrainedWindowList) for testing
@@ -615,7 +622,7 @@ class TabContents : public PageNavigator,
// Called by a derived class when the TabContents is resized, causing
// suppressed constrained web popups to be repositioned to the new bounds
// if necessary.
- void RepositionSupressedPopupsToFit(const gfx::Size& new_size);
+ void RepositionSupressedPopupsToFit();
// Whether we have a notification AND the notification owns popups windows.
// (We keep the notification object around even when it's not shown since it
@@ -971,8 +978,7 @@ class TabContents : public PageNavigator,
// Data for shelves and stuff ------------------------------------------------
// ConstrainedWindow with additional methods for managing blocked
- // popups. This pointer also goes in |child_windows_| for ownership,
- // repositioning, etc.
+ // popups.
BlockedPopupContainer* blocked_popups_;
// Delegates for InfoBars associated with this TabContents.
diff --git a/chrome/browser/tab_contents/tab_contents_view_win.cc b/chrome/browser/tab_contents/tab_contents_view_win.cc
index 15481b5..a5ec7f4 100644
--- a/chrome/browser/tab_contents/tab_contents_view_win.cc
+++ b/chrome/browser/tab_contents/tab_contents_view_win.cc
@@ -570,7 +570,7 @@ void TabContentsViewWin::WasSized(const gfx::Size& size) {
tab_contents()->render_widget_host_view()->SetSize(size);
// TODO(brettw) this function can probably be moved to this class.
- tab_contents()->RepositionSupressedPopupsToFit(size);
+ tab_contents()->RepositionSupressedPopupsToFit();
}
bool TabContentsViewWin::ScrollZoom(int scroll_type) {
diff --git a/chrome/browser/views/blocked_popup_container.cc b/chrome/browser/views/blocked_popup_container.cc
index fba9780..38fa3a5 100644
--- a/chrome/browser/views/blocked_popup_container.cc
+++ b/chrome/browser/views/blocked_popup_container.cc
@@ -11,6 +11,7 @@
#include "chrome/browser/views/blocked_popup_container.h"
#include <math.h>
+#include <windows.h>
#include "app/gfx/canvas.h"
#include "app/gfx/path.h"
@@ -21,19 +22,14 @@
#include "chrome/browser/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/notification_service.h"
-#include "chrome/common/pref_names.h"
-#include "chrome/common/pref_service.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "views/background.h"
#include "views/controls/button/image_button.h"
-namespace {
-// A number larger than the internal popup count on the Renderer; meant for
-// preventing a compromised renderer from exhausting GDI memory by spawning
-// infinite windows.
-const int kImpossibleNumberOfPopups = 30;
+#include "views/controls/scrollbar/native_scroll_bar.h"
+namespace {
// The minimal border around the edge of the notification.
const int kSmallPadding = 2;
@@ -78,10 +74,10 @@ const SkScalar kRoundedCornerRad[8] = {
0
};
-}
+} // namespace
BlockedPopupContainerView::BlockedPopupContainerView(
- BlockedPopupContainer* container)
+ BlockedPopupContainerImpl* container)
: container_(container) {
ResourceBundle &resource_bundle = ResourceBundle::GetSharedInstance();
@@ -200,7 +196,8 @@ void BlockedPopupContainerView::ButtonPressed(views::Button* sender) {
if (!hosts.empty() && (popup_count > 0))
launch_menu_->AppendSeparator();
for (size_t i = 0; i < hosts.size(); ++i) {
- launch_menu_->AppendMenuItem(kImpossibleNumberOfPopups + i + 1,
+ launch_menu_->AppendMenuItem(
+ BlockedPopupContainer::kImpossibleNumberOfPopups + i + 1,
l10n_util::GetStringF(IDS_POPUP_HOST_FORMAT, hosts[i]),
views::Menu::NORMAL);
}
@@ -215,9 +212,9 @@ void BlockedPopupContainerView::ButtonPressed(views::Button* sender) {
}
bool BlockedPopupContainerView::IsItemChecked(int id) const {
- if (id > kImpossibleNumberOfPopups) {
+ if (id > BlockedPopupContainer::kImpossibleNumberOfPopups) {
return container_->IsHostWhitelisted(static_cast<size_t>(
- id - kImpossibleNumberOfPopups - 1));
+ id - BlockedPopupContainer::kImpossibleNumberOfPopups - 1));
}
return false;
@@ -226,114 +223,29 @@ bool BlockedPopupContainerView::IsItemChecked(int id) const {
void BlockedPopupContainerView::ExecuteCommand(int id) {
DCHECK_GT(id, 0);
size_t id_size_t = static_cast<size_t>(id);
- if (id_size_t > kImpossibleNumberOfPopups) {
+ if (id_size_t > BlockedPopupContainer::kImpossibleNumberOfPopups) {
// Decrement id since all index based commands have 1 added to them. (See
// ButtonPressed() for detail).
container_->ToggleWhitelistingForHost(
- id_size_t - kImpossibleNumberOfPopups - 1);
+ id_size_t - BlockedPopupContainer::kImpossibleNumberOfPopups - 1);
} else {
container_->LaunchPopupAtIndex(id_size_t - 1);
}
}
-BlockedPopupContainer::~BlockedPopupContainer() {
-}
-
-// static
-void BlockedPopupContainer::RegisterUserPrefs(PrefService* prefs) {
- prefs->RegisterListPref(prefs::kPopupWhitelistedHosts);
+BlockedPopupContainerImpl::~BlockedPopupContainerImpl() {
}
// static
BlockedPopupContainer* BlockedPopupContainer::Create(
TabContents* owner, Profile* profile, const gfx::Point& initial_anchor) {
- BlockedPopupContainer* container =
- new BlockedPopupContainer(owner, profile->GetPrefs());
+ BlockedPopupContainerImpl* container =
+ new BlockedPopupContainerImpl(owner, profile->GetPrefs());
container->Init(initial_anchor);
return container;
}
-void BlockedPopupContainer::AddTabContents(TabContents* tab_contents,
- const gfx::Rect& bounds,
- const std::string& host) {
- // Show whitelisted popups immediately.
- bool whitelisted = !!whitelist_.count(host);
- if (whitelisted)
- owner_->AddNewContents(tab_contents, NEW_POPUP, bounds, true, GURL());
-
- if (has_been_dismissed_) {
- // Don't want to show any other UI.
- if (!whitelisted)
- delete tab_contents; // Discard blocked popups entirely.
- return;
- }
-
- if (whitelisted) {
- // Listen for this popup's destruction, so if the user closes it manually,
- // we'll know to stop caring about it.
- registrar_.Add(this, NotificationType::TAB_CONTENTS_DESTROYED,
- Source<TabContents>(tab_contents));
-
- unblocked_popups_[tab_contents] = host;
- } else {
- if (blocked_popups_.size() >= kImpossibleNumberOfPopups) {
- delete tab_contents;
- LOG(INFO) << "Warning: Renderer is sending more popups to us than should "
- "be possible. Renderer compromised?";
- return;
- }
- blocked_popups_.push_back(BlockedPopup(tab_contents, bounds, host));
-
- tab_contents->set_delegate(this);
- }
-
- PopupHosts::const_iterator i(popup_hosts_.find(host));
- if (i == popup_hosts_.end())
- popup_hosts_[host] = whitelisted;
- else
- DCHECK_EQ(whitelisted, i->second);
-
- // Update UI.
- container_view_->UpdateLabel();
- SetWindowPos(HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
- if (!Animation::IsAnimating() && visibility_percentage_ < 1.0) {
- in_show_animation_ = true;
- Animation::SetDuration(kShowAnimationDurationMS);
- Animation::Start();
- }
- owner_->PopupNotificationVisibilityChanged(true);
-}
-
-void BlockedPopupContainer::LaunchPopupAtIndex(size_t index) {
- if (index >= blocked_popups_.size())
- return;
-
- // Open the popup.
- BlockedPopups::iterator i(blocked_popups_.begin() + index);
- TabContents* tab_contents = i->tab_contents;
- tab_contents->set_delegate(NULL);
- owner_->AddNewContents(tab_contents, NEW_POPUP, i->bounds, true, GURL());
-
- const std::string& host = i->host;
- if (!host.empty()) {
- // Listen for this popup's destruction, so if the user closes it manually,
- // we'll know to stop caring about it.
- registrar_.Add(this, NotificationType::TAB_CONTENTS_DESTROYED,
- Source<TabContents>(tab_contents));
-
- // Add the popup to the unblocked list. (Do this before the below call!)
- unblocked_popups_[tab_contents] = i->host;
- }
-
- // Remove the popup from the blocked list.
- EraseDataForPopupAndUpdateUI(i);
-}
-
-size_t BlockedPopupContainer::GetBlockedPopupCount() const {
- return blocked_popups_.size();
-}
-
-void BlockedPopupContainer::GetURLAndTitleForPopup(size_t index,
+void BlockedPopupContainerImpl::GetURLAndTitleForPopup(size_t index,
std::wstring* url,
std::wstring* title) const {
DCHECK(url);
@@ -344,7 +256,7 @@ void BlockedPopupContainer::GetURLAndTitleForPopup(size_t index,
*title = UTF16ToWideHack(tab_contents->GetTitle());
}
-std::vector<std::wstring> BlockedPopupContainer::GetHosts() const {
+std::vector<std::wstring> BlockedPopupContainerImpl::GetHosts() const {
std::vector<std::wstring> hosts;
for (PopupHosts::const_iterator i(popup_hosts_.begin());
i != popup_hosts_.end(); ++i)
@@ -352,187 +264,61 @@ std::vector<std::wstring> BlockedPopupContainer::GetHosts() const {
return hosts;
}
-bool BlockedPopupContainer::IsHostWhitelisted(size_t index) const {
- PopupHosts::const_iterator i(ConvertHostIndexToIterator(index));
- return (i == popup_hosts_.end()) ? false : i->second;
-}
-
-void BlockedPopupContainer::ToggleWhitelistingForHost(size_t index) {
- PopupHosts::const_iterator i(ConvertHostIndexToIterator(index));
- const std::string& host = i->first;
- bool should_whitelist = !i->second;
- popup_hosts_[host] = should_whitelist;
-
- ListValue* whitelist_pref =
- prefs_->GetMutableList(prefs::kPopupWhitelistedHosts);
- if (should_whitelist) {
- whitelist_.insert(host);
- whitelist_pref->Append(new StringValue(host));
-
- // Open the popups in order.
- for (size_t j = 0; j < blocked_popups_.size(); ) {
- if (blocked_popups_[j].host == host)
- LaunchPopupAtIndex(j); // This shifts the rest of the entries down.
- else
- ++j;
- }
- } else {
- // Remove from whitelist.
- whitelist_.erase(host);
- whitelist_pref->Remove(StringValue(host));
-
- for (UnblockedPopups::iterator i(unblocked_popups_.begin());
- i != unblocked_popups_.end(); ) {
- TabContents* tab_contents = i->first;
- TabContentsDelegate* delegate = tab_contents->delegate();
- if ((i->second == host) && delegate->IsPopup(tab_contents)) {
- // Convert the popup back into a blocked popup.
- delegate->DetachContents(tab_contents);
- tab_contents->set_delegate(this);
-
- // Add the popup to the blocked list. (Do this before the below call!)
- gfx::Rect bounds;
- tab_contents->GetContainerBounds(&bounds);
- blocked_popups_.push_back(BlockedPopup(tab_contents, bounds, host));
-
- // Remove the popup from the unblocked list.
- i = EraseDataForPopupAndUpdateUI(i);
- } else {
- ++i;
- }
- }
- }
-}
-
-void BlockedPopupContainer::CloseAll() {
- ClearData();
- HideSelf();
-}
-
// Overridden from ConstrainedWindow:
-void BlockedPopupContainer::CloseConstrainedWindow() {
+void BlockedPopupContainerImpl::Destroy() {
ClearData();
-
- // Broadcast to all observers of NOTIFY_CWINDOW_CLOSED.
- // One example of such an observer is AutomationCWindowTracker in the
- // automation component.
- NotificationService::current()->Notify(NotificationType::CWINDOW_CLOSED,
- Source<ConstrainedWindow>(this),
- NotificationService::NoDetails());
-
Close();
}
-void BlockedPopupContainer::RepositionConstrainedWindowTo(
- const gfx::Point& anchor_point) {
- anchor_point_ = anchor_point;
- SetPosition();
-}
+void BlockedPopupContainerImpl::RepositionBlockedPopupContainer(
+ gfx::NativeView view) {
+ if (::IsWindow(view)) {
+ CRect client_rect;
+ ::GetClientRect(view, &client_rect);
-// Overridden from TabContentsDelegate:
-void BlockedPopupContainer::OpenURLFromTab(TabContents* source,
- const GURL& url,
- const GURL& referrer,
- WindowOpenDisposition disposition,
- PageTransition::Type transition) {
- owner_->OpenURL(url, referrer, disposition, transition);
-}
+ // TODO(erg): There's no way to detect whether scroll bars are
+ // visible, so for beta, we're just going to assume that the
+ // vertical scroll bar is visible, and not care about covering up
+ // the horizontal scroll bar. Fixing this is half of
+ // http://b/1118139.
+ gfx::Point anchor_position(
+ client_rect.Width() -
+ views::NativeScrollBar::GetVerticalScrollBarWidth(),
+ client_rect.Height());
-void BlockedPopupContainer::AddNewContents(TabContents* source,
- TabContents* new_contents,
- WindowOpenDisposition disposition,
- const gfx::Rect& initial_position,
- bool user_gesture) {
- owner_->AddNewContents(new_contents, disposition, initial_position,
- user_gesture, GURL());
-}
-
-void BlockedPopupContainer::CloseContents(TabContents* source) {
- for (BlockedPopups::iterator it = blocked_popups_.begin();
- it != blocked_popups_.end(); ++it) {
- TabContents* tab_contents = it->tab_contents;
- if (tab_contents == source) {
- tab_contents->set_delegate(NULL);
- EraseDataForPopupAndUpdateUI(it);
- delete tab_contents;
- break;
- }
- }
-}
-
-void BlockedPopupContainer::MoveContents(TabContents* source,
- const gfx::Rect& new_bounds) {
- for (BlockedPopups::iterator it = blocked_popups_.begin();
- it != blocked_popups_.end(); ++it) {
- if (it->tab_contents == source) {
- it->bounds = new_bounds;
- break;
- }
+ RepositionWindowTo(anchor_position);
}
}
-bool BlockedPopupContainer::IsPopup(TabContents* source) {
- return true;
-}
-
-TabContents* BlockedPopupContainer::GetConstrainingContents(
- TabContents* source) {
- return owner_;
-}
-
-ExtensionFunctionDispatcher* BlockedPopupContainer::
- CreateExtensionFunctionDispatcher(RenderViewHost* render_view_host,
- const std::string& extension_id) {
- return new ExtensionFunctionDispatcher(render_view_host, NULL, extension_id);
-}
-
// private:
-BlockedPopupContainer::BlockedPopupContainer(TabContents* owner,
- PrefService* prefs)
- : Animation(kFramerate, NULL),
- owner_(owner),
- prefs_(prefs),
+BlockedPopupContainerImpl::BlockedPopupContainerImpl(TabContents* owner,
+ PrefService* prefs)
+ : BlockedPopupContainer(owner, prefs),
+ Animation(kFramerate, NULL),
container_view_(NULL),
- has_been_dismissed_(false),
in_show_animation_(false),
visibility_percentage_(0) {
- // Copy whitelist pref into local member that's easier to use.
- const ListValue* whitelist_pref =
- prefs_->GetList(prefs::kPopupWhitelistedHosts);
- // Careful: The returned value could be NULL if the pref has never been set.
- if (whitelist_pref != NULL) {
- for (ListValue::const_iterator i(whitelist_pref->begin());
- i != whitelist_pref->end(); ++i) {
- std::string host;
- (*i)->GetAsString(&host);
- whitelist_.insert(host);
- }
- }
}
-void BlockedPopupContainer::AnimateToState(double state) {
- visibility_percentage_ = in_show_animation_ ? state : (1 - state);
+void BlockedPopupContainerImpl::RepositionWindowTo(
+ const gfx::Point& anchor_point) {
+ anchor_point_ = anchor_point;
SetPosition();
}
-void BlockedPopupContainer::Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- DCHECK(type == NotificationType::TAB_CONTENTS_DESTROYED);
- TabContents* tab_contents = Source<TabContents>(source).ptr();
- UnblockedPopups::iterator i(unblocked_popups_.find(tab_contents));
- DCHECK(i != unblocked_popups_.end());
- EraseDataForPopupAndUpdateUI(i);
+void BlockedPopupContainerImpl::AnimateToState(double state) {
+ visibility_percentage_ = in_show_animation_ ? state : (1 - state);
+ SetPosition();
}
-void BlockedPopupContainer::OnFinalMessage(HWND window) {
- owner_->WillClose(this);
+void BlockedPopupContainerImpl::OnFinalMessage(HWND window) {
+ GetConstrainingContents(NULL)->WillCloseBlockedPopupContainer(this);
ClearData();
WidgetWin::OnFinalMessage(window);
}
-void BlockedPopupContainer::OnSize(UINT param, const CSize& size) {
+void BlockedPopupContainerImpl::OnSize(UINT param, const CSize& size) {
// Set the window region so we have rounded corners on the top.
SkRect rect;
rect.set(0, 0, SkIntToScalar(size.cx), SkIntToScalar(size.cy));
@@ -543,24 +329,41 @@ void BlockedPopupContainer::OnSize(UINT param, const CSize& size) {
ChangeSize(param, size);
}
-void BlockedPopupContainer::Init(const gfx::Point& initial_anchor) {
+void BlockedPopupContainerImpl::Init(const gfx::Point& initial_anchor) {
container_view_ = new BlockedPopupContainerView(this);
container_view_->SetVisible(true);
set_window_style(WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN);
- WidgetWin::Init(owner_->GetNativeView(), gfx::Rect(), false);
+ WidgetWin::Init(GetConstrainingContents(NULL)->GetNativeView(), gfx::Rect(),
+ false);
SetContentsView(container_view_);
- RepositionConstrainedWindowTo(initial_anchor);
+ RepositionWindowTo(initial_anchor);
}
-void BlockedPopupContainer::HideSelf() {
+void BlockedPopupContainerImpl::ShowSelf() {
+ SetWindowPos(HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
+ if (!Animation::IsAnimating() && visibility_percentage_ < 1.0) {
+ in_show_animation_ = true;
+ Animation::SetDuration(kShowAnimationDurationMS);
+ Animation::Start();
+ }
+}
+
+void BlockedPopupContainerImpl::HideSelf() {
in_show_animation_ = false;
Animation::SetDuration(kHideAnimationDurationMS);
Animation::Start();
- owner_->PopupNotificationVisibilityChanged(false);
+ BlockedPopupContainer::HideSelf();
+}
+
+void BlockedPopupContainerImpl::UpdateLabel() {
+ if (blocked_popups_.empty() && unblocked_popups_.empty())
+ HideSelf();
+ else
+ container_view_->UpdateLabel();
}
-void BlockedPopupContainer::SetPosition() {
+void BlockedPopupContainerImpl::SetPosition() {
gfx::Size size = container_view_->GetPreferredSize();
int base_x = anchor_point_.x() - size.width();
int base_y = anchor_point_.y() - size.height();
@@ -590,103 +393,3 @@ void BlockedPopupContainer::SetPosition() {
SWP_NOMOVE | SWP_NOSIZE | SWP_HIDEWINDOW);
}
}
-
-void BlockedPopupContainer::ClearData() {
- for (BlockedPopups::iterator i(blocked_popups_.begin());
- i != blocked_popups_.end(); ++i) {
- TabContents* tab_contents = i->tab_contents;
- tab_contents->set_delegate(NULL);
- delete tab_contents;
- }
- blocked_popups_.clear();
-
- registrar_.RemoveAll();
- unblocked_popups_.clear();
-
- popup_hosts_.clear();
-}
-
-BlockedPopupContainer::PopupHosts::const_iterator
- BlockedPopupContainer::ConvertHostIndexToIterator(size_t index) const {
- if (index >= popup_hosts_.size())
- return popup_hosts_.end();
- // If only there was a std::map::const_iterator::operator +=() ...
- PopupHosts::const_iterator i(popup_hosts_.begin());
- for (size_t j = 0; j < index; ++j)
- ++i;
- return i;
-}
-
-void BlockedPopupContainer::EraseDataForPopupAndUpdateUI(
- BlockedPopups::iterator i) {
- // Erase the host if this is the last popup for that host.
- const std::string& host = i->host;
- if (!host.empty()) {
- bool should_erase_host = true;
- for (BlockedPopups::const_iterator j(blocked_popups_.begin());
- j != blocked_popups_.end(); ++j) {
- if ((j != i) && (j->host == host)) {
- should_erase_host = false;
- break;
- }
- }
- if (should_erase_host) {
- for (UnblockedPopups::const_iterator j(unblocked_popups_.begin());
- j != unblocked_popups_.end(); ++j) {
- if (j->second == host) {
- should_erase_host = false;
- break;
- }
- }
- if (should_erase_host)
- popup_hosts_.erase(host);
- }
- }
-
- // Erase the popup and update the UI.
- blocked_popups_.erase(i);
- if (blocked_popups_.empty() && unblocked_popups_.empty())
- HideSelf();
- else
- container_view_->UpdateLabel();
-}
-
-BlockedPopupContainer::UnblockedPopups::iterator
- BlockedPopupContainer::EraseDataForPopupAndUpdateUI(
- UnblockedPopups::iterator i) {
- // Stop listening for this popup's destruction.
- registrar_.Remove(this, NotificationType::TAB_CONTENTS_DESTROYED,
- Source<TabContents>(i->first));
-
- // Erase the host if this is the last popup for that host.
- const std::string& host = i->second;
- if (!host.empty()) {
- bool should_erase_host = true;
- for (UnblockedPopups::const_iterator j(unblocked_popups_.begin());
- j != unblocked_popups_.end(); ++j) {
- if ((j != i) && (j->second == host)) {
- should_erase_host = false;
- break;
- }
- }
- if (should_erase_host) {
- for (BlockedPopups::const_iterator j(blocked_popups_.begin());
- j != blocked_popups_.end(); ++j) {
- if (j->host == host) {
- should_erase_host = false;
- break;
- }
- }
- if (should_erase_host)
- popup_hosts_.erase(host);
- }
- }
-
- // Erase the popup and update the UI.
- UnblockedPopups::iterator next_popup = unblocked_popups_.erase(i);
- if (blocked_popups_.empty() && unblocked_popups_.empty())
- HideSelf();
- else
- container_view_->UpdateLabel();
- return next_popup;
-}
diff --git a/chrome/browser/views/blocked_popup_container.h b/chrome/browser/views/blocked_popup_container.h
index 291b0ee..74d3504 100644
--- a/chrome/browser/views/blocked_popup_container.h
+++ b/chrome/browser/views/blocked_popup_container.h
@@ -2,11 +2,6 @@
// source code is governed by a BSD-style license that can be found in the
// LICENSE file.
-// Defines the public interface for the blocked popup notifications. This
-// interface should only be used by TabContents. Users and subclasses of
-// TabContents should use the appropriate methods on TabContents to access
-// information about blocked popups.
-
#ifndef CHROME_BROWSER_VIEWS_BLOCKED_POPUP_CONTAINER_H_
#define CHROME_BROWSER_VIEWS_BLOCKED_POPUP_CONTAINER_H_
@@ -15,17 +10,17 @@
#include <vector>
#include "app/animation.h"
+#include "base/gfx/native_widget_types.h"
#include "base/gfx/rect.h"
-#include "chrome/browser/tab_contents/constrained_window.h"
+#include "chrome/browser/blocked_popup_container.h"
#include "chrome/browser/tab_contents/tab_contents_delegate.h"
-#include "chrome/common/notification_registrar.h"
#include "views/controls/button/button.h"
#include "views/controls/button/menu_button.h"
#include "views/controls/menu/menu.h"
#include "views/view.h"
#include "views/widget/widget_win.h"
-class BlockedPopupContainer;
+class BlockedPopupContainerImpl;
class PrefService;
class Profile;
class TabContents;
@@ -41,7 +36,7 @@ class BlockedPopupContainerView : public views::View,
public views::ButtonListener,
public views::Menu::Delegate {
public:
- explicit BlockedPopupContainerView(BlockedPopupContainer* container);
+ explicit BlockedPopupContainerView(BlockedPopupContainerImpl* container);
~BlockedPopupContainerView();
// Sets the label on the menu button
@@ -70,7 +65,7 @@ class BlockedPopupContainerView : public views::View,
private:
// Our owner and HWND parent.
- BlockedPopupContainer* container_;
+ BlockedPopupContainerImpl* container_;
// The button which brings up the popup menu.
views::MenuButton* popup_count_label_;
@@ -87,32 +82,14 @@ class BlockedPopupContainerView : public views::View,
// Takes ownership of TabContents that are unrequested popup windows and
// presents an interface to the user for launching them. (Or never showing them
// again).
-class BlockedPopupContainer : public Animation,
- public ConstrainedWindow,
- public NotificationObserver,
- public TabContentsDelegate,
- public views::WidgetWin {
+//
+// TODO(erg): When this class goes away, whatever is replaced shouldn't
+// multiply inherit.
+class BlockedPopupContainerImpl : public BlockedPopupContainer,
+ public Animation,
+ public views::WidgetWin {
public:
- virtual ~BlockedPopupContainer();
-
- static void RegisterUserPrefs(PrefService* prefs);
-
- // Creates a BlockedPopupContainer, anchoring the container to the lower
- // right corner.
- static BlockedPopupContainer* Create(
- TabContents* owner, Profile* profile, const gfx::Point& initial_anchor);
-
- // Adds a popup to this container. |bounds| are the window bounds requested by
- // the popup window.
- void AddTabContents(TabContents* tab_contents,
- const gfx::Rect& bounds,
- const std::string& host);
-
- // Shows the blocked popup at index |index|.
- void LaunchPopupAtIndex(size_t index);
-
- // Returns the number of blocked popups
- size_t GetBlockedPopupCount() const;
+ virtual ~BlockedPopupContainerImpl();
// Returns the URL and title for popup |index|, used to construct a string for
// display.
@@ -123,127 +100,25 @@ class BlockedPopupContainer : public Animation,
// Returns the names of hosts showing popups.
std::vector<std::wstring> GetHosts() const;
- // Returns true if host |index| is whitelisted. Returns false if |index| is
- // invalid.
- bool IsHostWhitelisted(size_t index) const;
-
- // If host |index| is currently whitelisted, un-whitelists it. Otherwise,
- // whitelists it and opens all blocked popups from it.
- void ToggleWhitelistingForHost(size_t index);
+ virtual void Destroy();
- // Deletes all popups and hides the interface parts.
- void CloseAll();
+ virtual void RepositionBlockedPopupContainer(gfx::NativeView view);
- // Called to force this container to never show itself again.
- void set_dismissed() { has_been_dismissed_ = true; }
-
- // Overridden from ConstrainedWindow:
+ private:
+ friend class BlockedPopupContainer;
- // Closes all of our blocked popups and then closes the BlockedPopupContainer.
- virtual void CloseConstrainedWindow();
+ // Creates a container for a certain TabContents.
+ BlockedPopupContainerImpl(TabContents* owner, PrefService* prefs);
// Repositions our blocked popup notification so that the lower right corner
// is at |anchor_point|.
- virtual void RepositionConstrainedWindowTo(const gfx::Point& anchor_point);
-
- // A BlockedPopupContainer is part of the HWND heiarchy and therefore doesn't
- // need to manually respond to hide and show events.
- virtual void WasHidden() { }
- virtual void DidBecomeSelected() { }
-
- // Debugging accessors only called from the unit tests.
- virtual std::wstring GetWindowTitle() const {
- return container_view_->label();
- }
- virtual const gfx::Rect& GetCurrentBounds() const { return bounds_; }
-
- // Overridden from TabContentsDelegate:
-
- // Forwards OpenURLFromTab to our |owner_|.
- virtual void OpenURLFromTab(TabContents* source,
- const GURL& url, const GURL& referrer,
- WindowOpenDisposition disposition,
- PageTransition::Type transition);
-
- // Ignored; BlockedPopupContainer doesn't display a throbber.
- virtual void NavigationStateChanged(const TabContents* source,
- unsigned changed_flags) { }
-
- // Forwards AddNewContents to our |owner_|.
- virtual void AddNewContents(TabContents* source,
- TabContents* new_contents,
- WindowOpenDisposition disposition,
- const gfx::Rect& initial_position,
- bool user_gesture);
-
- // Ignore activation requests from the TabContents we're blocking.
- virtual void ActivateContents(TabContents* contents) { }
-
- // Ignored; BlockedPopupContainer doesn't display a throbber.
- virtual void LoadingStateChanged(TabContents* source) { }
-
- // Removes |source| from our internal list of blocked popups.
- virtual void CloseContents(TabContents* source);
-
- // Changes the opening rectangle associated with |source|.
- virtual void MoveContents(TabContents* source, const gfx::Rect& new_bounds);
-
- // Always returns true.
- virtual bool IsPopup(TabContents* source);
-
- // Returns our |owner_|.
- virtual TabContents* GetConstrainingContents(TabContents* source);
-
- // Ignored; BlockedPopupContainer doesn't display a toolbar.
- virtual void ToolbarSizeChanged(TabContents* source, bool is_animating) { }
-
- // Ignored; BlockedPopupContainer doesn't display a bookmarking star.
- virtual void URLStarredChanged(TabContents* source, bool starred) { }
-
- // Ignored; BlockedPopupContainer doesn't display a URL bar.
- virtual void UpdateTargetURL(TabContents* source, const GURL& url) { }
-
- // Creates an ExtensionFunctionDispatcher that has no browser
- virtual ExtensionFunctionDispatcher* CreateExtensionFunctionDispatcher(
- RenderViewHost* render_view_host,
- const std::string& extension_id);
-
- private:
- struct BlockedPopup {
- BlockedPopup(TabContents* tab_contents,
- const gfx::Rect& bounds,
- const std::string& host)
- : tab_contents(tab_contents), bounds(bounds), host(host) {
- }
-
- TabContents* tab_contents;
- gfx::Rect bounds;
- std::string host;
- };
- typedef std::vector<BlockedPopup> BlockedPopups;
-
- // TabContents is the popup contents. string is opener hostname.
- typedef std::map<TabContents*, std::string> UnblockedPopups;
-
- // string is hostname. bool is whitelisted status.
- typedef std::map<std::string, bool> PopupHosts;
-
- // string is hostname.
- typedef std::set<std::string> Whitelist;
-
- // Creates a container for a certain TabContents.
- BlockedPopupContainer(TabContents* owner, PrefService* prefs);
+ void RepositionWindowTo(const gfx::Point& anchor_point);
// Overridden from Animation:
- // Changes the visibility percentage of the BlockedPopupContainer. This is
+ // Changes the visibility percentage of the BlockedPopupContainerImpl. This is
// called while animating in or out.
virtual void AnimateToState(double state);
- // Overridden from notificationObserver:
- virtual void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
-
// Overridden from views::WidgetWin:
// Alerts our |owner_| that we are closing ourselves. Cleans up any remaining
@@ -257,59 +132,22 @@ class BlockedPopupContainer : public Animation,
// browser window.
void Init(const gfx::Point& initial_anchor);
+ // Shows the UI.
+ virtual void ShowSelf();
+
// Hides the UI portion of the container.
- void HideSelf();
+ virtual void HideSelf();
+
+ virtual void UpdateLabel();
// Sets our position, based on our |anchor_point_| and on our
// |visibility_percentage_|. This method is called whenever either of those
// change.
void SetPosition();
- // Deletes all local state.
- void ClearData();
-
- // Helper function to convert a host index (which the view uses) into an
- // iterator into |popup_hosts_|. Returns popup_hosts_.end() if |index| is
- // invalid.
- PopupHosts::const_iterator ConvertHostIndexToIterator(size_t index) const;
-
- // Removes the popup at |i| from the blocked popup list. If this popup's host
- // is not otherwised referenced on either popup list, removes the host from
- // the host list. Updates the view's label to match the new state.
- void EraseDataForPopupAndUpdateUI(BlockedPopups::iterator i);
-
- // Same as above, but works on the unblocked popup list, and returns the
- // iterator that results from calling erase().
- UnblockedPopups::iterator EraseDataForPopupAndUpdateUI(
- UnblockedPopups::iterator i);
-
- // The TabContents that owns and constrains this BlockedPopupContainer.
- TabContents* owner_;
-
- // The PrefService we can query to find out what's on the whitelist.
- PrefService* prefs_;
-
- // Registrar to handle notifications we care about.
- NotificationRegistrar registrar_;
-
- // The whitelisted hosts, which we allow to open popups directly.
- Whitelist whitelist_;
-
- // Information about all blocked popups.
- BlockedPopups blocked_popups_;
-
- // Information about all unblocked popups.
- UnblockedPopups unblocked_popups_;
-
- // Information about all popup hosts.
- PopupHosts popup_hosts_;
-
// Our associated view object.
BlockedPopupContainerView* container_view_;
- // Once the container is hidden, this is set to prevent it from reappearing.
- bool has_been_dismissed_;
-
// True while animating in; false while animating out.
bool in_show_animation_;
@@ -322,8 +160,6 @@ class BlockedPopupContainer : public Animation,
// The bottom right corner of where we should appear in our parent window.
gfx::Point anchor_point_;
-
- DISALLOW_IMPLICIT_CONSTRUCTORS(BlockedPopupContainer);
};
#endif
diff --git a/chrome/browser/views/constrained_window_impl_interactive_uitest.cc b/chrome/browser/views/constrained_window_impl_interactive_uitest.cc
index df8dd60..fcd7639 100644
--- a/chrome/browser/views/constrained_window_impl_interactive_uitest.cc
+++ b/chrome/browser/views/constrained_window_impl_interactive_uitest.cc
@@ -132,14 +132,6 @@ TEST_F(InteractiveConstrainedWindowTest, DontSpawnEndlessPopups) {
scoped_refptr<TabProxy> popup_tab(popup_browser->GetTab(0));
ASSERT_TRUE(popup_tab.get());
- int constrained_window_count = 0;
- ASSERT_TRUE(popup_tab->WaitForChildWindowCountToChange(
- 0, &constrained_window_count, 10000));
- ASSERT_EQ(1, constrained_window_count);
- scoped_refptr<ConstrainedWindowProxy> constrained_window(
- popup_tab->GetConstrainedWindow(0));
- ASSERT_TRUE(constrained_window.get());
-
// And now we spin, waiting to make sure that we don't spawn popup
// windows endlessly. The current limit is 25, so allowing for possible race
// conditions and one off errors, don't break out until we go over 30 popup
@@ -151,9 +143,7 @@ TEST_F(InteractiveConstrainedWindowTest, DontSpawnEndlessPopups) {
int times_slept = 0;
bool continuing = true;
while (continuing && popup_window_count < kMaxPopupWindows) {
- std::wstring title;
- ASSERT_TRUE(constrained_window->GetTitle(&title));
- ASSERT_TRUE(ParseCountOutOfTitle(title, &new_popup_window_count));
+ ASSERT_TRUE(popup_tab->GetBlockedPopupCount(&new_popup_window_count));
if (new_popup_window_count == popup_window_count) {
if (times_slept == 10) {
continuing = false;
@@ -180,8 +170,6 @@ TEST_F(InteractiveConstrainedWindowTest, WindowOpenWindowClosePopup) {
ASSERT_TRUE(automation()->WaitForWindowCountToBecome(2, 5000));
- PlatformThread::Sleep(1000);
-
// Make sure we have a blocked popup notification
scoped_refptr<BrowserProxy> popup_browser(automation()->GetBrowserWindow(1));
ASSERT_TRUE(popup_browser.get());
@@ -189,14 +177,7 @@ TEST_F(InteractiveConstrainedWindowTest, WindowOpenWindowClosePopup) {
ASSERT_TRUE(popup_window.get());
scoped_refptr<TabProxy> popup_tab(popup_browser->GetTab(0));
ASSERT_TRUE(popup_tab.get());
- scoped_refptr<ConstrainedWindowProxy> popup_notification(
- popup_tab->GetConstrainedWindow(0));
- ASSERT_TRUE(popup_notification.get());
- std::wstring title;
- ASSERT_TRUE(popup_notification->GetTitle(&title));
- int count = 0;
- ASSERT_TRUE(ParseCountOutOfTitle(title, &count));
- ASSERT_EQ(1, count);
+ ASSERT_TRUE(popup_tab->WaitForBlockedPopupCountToChangeTo(1, 1000));
// Ensure we didn't close the first popup window.
ASSERT_FALSE(automation()->WaitForWindowCountToBecome(1, 3000));
@@ -214,13 +195,8 @@ TEST_F(InteractiveConstrainedWindowTest, BlockAlertFromBlockedPopup) {
ASSERT_EQ(1, browser_window_count);
// Ensure one blocked popup window: the popup didn't escape.
- scoped_refptr<ConstrainedWindowProxy> popup_notification(
- tab_->GetConstrainedWindow(0));
- ASSERT_TRUE(popup_notification.get());
- std::wstring title;
- ASSERT_TRUE(popup_notification->GetTitle(&title));
int popup_count = 0;
- ASSERT_TRUE(ParseCountOutOfTitle(title, &popup_count));
+ ASSERT_TRUE(tab_->GetBlockedPopupCount(&popup_count));
ASSERT_EQ(1, popup_count);
}