summaryrefslogtreecommitdiffstats
path: root/chrome/browser/blocked_popup_container.cc
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/blocked_popup_container.cc
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/blocked_popup_container.cc')
-rw-r--r--chrome/browser/blocked_popup_container.cc337
1 files changed, 337 insertions, 0 deletions
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);
+}