diff options
author | pkasting@chromium.org <pkasting@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-06 23:46:22 +0000 |
---|---|---|
committer | pkasting@chromium.org <pkasting@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-06 23:46:22 +0000 |
commit | 2c4410df7aaa0ed2c50edb1107c085098124fc99 (patch) | |
tree | 58f235bf5a6fb9f35053f08260fc91a3ff5c00ff /chrome | |
parent | 21e9e6d3296ea4198352619ed7a71cb92bc845de (diff) | |
download | chromium_src-2c4410df7aaa0ed2c50edb1107c085098124fc99.zip chromium_src-2c4410df7aaa0ed2c50edb1107c085098124fc99.tar.gz chromium_src-2c4410df7aaa0ed2c50edb1107c085098124fc99.tar.bz2 |
Popup whitelisting checkpoint.
This provides some basic UI for the popup whitelist. The actual whitelist is completely unimplemented and just has TODOs at the hook points. The actual blocking behavior of the browser is unchanged.
The popup blocker bubble menu now gets an extra section below the popups with checkable "Always show popups from <host>" items (usually one, can be more on pages with popups from iframes from different hosts). Clicking one of these will whitelist a hostname and open its popups, and remove it from the menu. When navigating to a page with whitelisted popups, the popup blocker bubble is opened (showing "Blocked Popups: 0", text subject to change), and the menu contains the checked entr(y/ies) relevant to these page. Clicking one of these un-whitelists the host and removes the entry from the menu (closing the menu if that was the last such entry).
Known UI questions:
* Wording is all speculative
* Should manually closing all popups associated with a whitelisted site remove that entry/close the menu automatically? (I suspect yes)
* Should un-whitelisting a site via the menu entry close its popups, just like whitelisting it opens them? (Not sure)
* Should menu items for sites stick around after toggling their whitelisting status, thus keeping the bubble onscreen until it's manually closed, the page is navigated, etc.? (While this is slightly more consistent, I suspect the answer is no)
BUG=11440
Review URL: http://codereview.chromium.org/113058
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@15475 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r-- | chrome/app/generated_resources.grd | 3 | ||||
-rw-r--r-- | chrome/browser/renderer_host/render_view_host.cc | 2 | ||||
-rw-r--r-- | chrome/browser/tab_contents/tab_contents.cc | 77 | ||||
-rw-r--r-- | chrome/browser/tab_contents/tab_contents.h | 30 | ||||
-rw-r--r-- | chrome/browser/views/blocked_popup_container.cc | 225 | ||||
-rw-r--r-- | chrome/browser/views/blocked_popup_container.h | 68 | ||||
-rw-r--r-- | chrome/common/render_messages_internal.h | 2 | ||||
-rw-r--r-- | chrome/renderer/render_view.cc | 8 | ||||
-rw-r--r-- | chrome/renderer/render_view.h | 4 |
9 files changed, 302 insertions, 117 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 6ff9aeb..683e65a 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd @@ -3716,6 +3716,9 @@ each locale. --> <message name="IDS_POPUP_TITLE_FORMAT" desc="Order of URL - Title on the popup"> <ph name="URL">$1</ph> - <ph name="WINDOW_TITLE">$2</ph> </message> + <message name="IDS_POPUP_HOST_FORMAT" desc="Checkable menu item to always allow popups from a particular hostname"> + Always show pop-ups from <ph name="URL">$1</ph> + </message> <!-- Multiple download warning--> <message name="IDS_MULTI_DOWNLOAD_WARNING" desc="Warning invoked if multiple downloads are attempted without user interaction."> diff --git a/chrome/browser/renderer_host/render_view_host.cc b/chrome/browser/renderer_host/render_view_host.cc index 8991f5f..b31181b 100644 --- a/chrome/browser/renderer_host/render_view_host.cc +++ b/chrome/browser/renderer_host/render_view_host.cc @@ -1092,7 +1092,7 @@ void RenderViewHost::DisassociateFromPopupCount() { } void RenderViewHost::PopupNotificationVisibilityChanged(bool visible) { - Send(new ViewMsg_PopupNotificationVisiblityChanged(routing_id(), visible)); + Send(new ViewMsg_PopupNotificationVisibilityChanged(routing_id(), visible)); } void RenderViewHost::OnMsgGoToEntryAtOffset(int offset) { diff --git a/chrome/browser/tab_contents/tab_contents.cc b/chrome/browser/tab_contents/tab_contents.cc index 743e1bd..14cdd22 100644 --- a/chrome/browser/tab_contents/tab_contents.cc +++ b/chrome/browser/tab_contents/tab_contents.cc @@ -791,16 +791,25 @@ void TabContents::AddNewContents(TabContents* new_contents, return; #if defined(OS_WIN) + bool constrain_popup = false; if ((disposition == NEW_POPUP) && !user_gesture && !CommandLine::ForCurrentProcess()->HasSwitch( switches::kDisablePopupBlocking)) { - // Unrequested popups from normal pages are constrained. - TabContents* popup_owner = this; + // Unrequested popups from normal pages are constrained unless they're in + // the whitelist. + std::string host; + if (creator_url.is_valid()) + host = creator_url.host(); + constrain_popup = true; // TODO(pkasting): Add whitelist + TabContents* our_owner = delegate_->GetConstrainingContents(this); - if (our_owner) - popup_owner = our_owner; - popup_owner->AddConstrainedPopup(new_contents, initial_pos); - } else { + TabContents* popup_owner = our_owner ? our_owner : this; + if (constrain_popup) + popup_owner->AddConstrainedPopup(new_contents, initial_pos, host); + else + popup_owner->OnPopupOpenedFromWhitelistedHost(host); + } + if (!constrain_popup) { new_contents->DisassociateFromPopupCount(); delegate_->AddNewContents(this, new_contents, disposition, initial_pos, @@ -816,28 +825,9 @@ void TabContents::AddNewContents(TabContents* new_contents, } #if defined(OS_WIN) -void TabContents::AddConstrainedPopup(TabContents* new_contents, - const gfx::Rect& initial_pos) { - if (!blocked_popups_) { - CRect client_rect; - GetClientRect(GetNativeView(), &client_rect); - gfx::Point anchor_position( - client_rect.Width() - - views::NativeScrollBar::GetVerticalScrollBarWidth(), - client_rect.Height()); - - blocked_popups_ = BlockedPopupContainer::Create( - this, profile(), anchor_position); - child_windows_.push_back(blocked_popups_); - } - - blocked_popups_->AddTabContents(new_contents, initial_pos); - PopupNotificationVisibilityChanged(ShowingBlockedPopupNotification()); -} - void TabContents::CloseAllSuppressedPopups() { if (blocked_popups_) - blocked_popups_->CloseAllPopups(); + blocked_popups_->CloseAll(); } #endif @@ -1142,6 +1132,12 @@ bool TabContents::IsActiveEntry(int32 page_id) { active_entry->page_id() == page_id); } +#if defined(OS_WIN) +void TabContents::SetWhitelistForHost(const std::string& host, bool whitelist) { + // TODO(pkasting): Add whitelist +} +#endif + // Notifies the RenderWidgetHost instance about the fact that the page is // loading, or done loading and calls the base implementation. void TabContents::SetIsLoading(bool is_loading, @@ -1174,6 +1170,33 @@ void TabContents::SetIsLoading(bool is_loading, } #if defined(OS_WIN) +void TabContents::CreateBlockedPopupContainerIfNecessary() { + if (blocked_popups_) + return; + + CRect client_rect; + GetClientRect(GetNativeView(), &client_rect); + gfx::Point anchor_position( + client_rect.Width() - views::NativeScrollBar::GetVerticalScrollBarWidth(), + client_rect.Height()); + blocked_popups_ = BlockedPopupContainer::Create(this, profile(), + anchor_position); + child_windows_.push_back(blocked_popups_); +} + +void TabContents::AddConstrainedPopup(TabContents* new_contents, + const gfx::Rect& initial_pos, + const std::string& host) { + CreateBlockedPopupContainerIfNecessary(); + blocked_popups_->AddTabContents(new_contents, initial_pos, host); + PopupNotificationVisibilityChanged(ShowingBlockedPopupNotification()); +} + +void TabContents::OnPopupOpenedFromWhitelistedHost(const std::string& host) { + CreateBlockedPopupContainerIfNecessary(); + blocked_popups_->OnPopupOpenedFromWhitelistedHost(host); +} + // 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 @@ -1192,7 +1215,7 @@ void TabContents::RepositionSupressedPopupsToFit(const gfx::Size& new_size) { bool TabContents::ShowingBlockedPopupNotification() const { return blocked_popups_ != NULL && - blocked_popups_->GetTabContentsCount() != 0; + blocked_popups_->GetBlockedPopupCount() != 0; } #endif // defined(OS_WIN) diff --git a/chrome/browser/tab_contents/tab_contents.h b/chrome/browser/tab_contents/tab_contents.h index 59549c4..ed063e2 100644 --- a/chrome/browser/tab_contents/tab_contents.h +++ b/chrome/browser/tab_contents/tab_contents.h @@ -341,11 +341,6 @@ class TabContents : public PageNavigator, bool user_gesture, const GURL& creator_url); - // Builds a ConstrainedWindow* for the incoming |new_contents| and - // adds it to child_windows_. - void AddConstrainedPopup(TabContents* new_contents, - const gfx::Rect& initial_pos); - // Closes all constrained windows that represent web popups that have not yet // been activated by the user and are as such auto-positioned in the bottom // right of the screen. This is a quick way for users to "clean up" a flurry @@ -570,6 +565,9 @@ class TabContents : public PageNavigator, render_view_host()->WindowMoveOrResizeStarted(); } + // Sets popup whitelisting state for |host| to |whitelist|. + void SetWhitelistForHost(const std::string& host, bool whitelist); + private: friend class NavigationController; // Used to access the child_windows_ (ConstrainedWindowList) for testing @@ -619,11 +617,28 @@ class TabContents : public PageNavigator, void SetIsLoading(bool is_loading, LoadNotificationDetails* details); + // Constructs |blocked_popups_| if need be. + void CreateBlockedPopupContainerIfNecessary(); + + // Adds the incoming |new_contents| to the |blocked_popups_| container. + void AddConstrainedPopup(TabContents* new_contents, + const gfx::Rect& initial_pos, + const std::string& host); + + // Notifies the |blocked_popups_| container that a popup has been opened from + // a particular whitelisted host. + void OnPopupOpenedFromWhitelistedHost(const std::string& host); + // 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); + // 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 + // determines whether to show itself). + bool ShowingBlockedPopupNotification() const; + // Releases the download shelf. This method is used by MigrateShelfFrom. void ReleaseDownloadShelf(); @@ -635,11 +650,6 @@ class TabContents : public PageNavigator, typedef std::vector<ConstrainedWindow*> ConstrainedWindowList; ConstrainedWindowList child_windows_; - // 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 - // determines whether to show itself). - bool ShowingBlockedPopupNotification() const; - // Expires InfoBars that need to be expired, according to the state carried // in |details|, in response to a new NavigationEntry being committed (the // user navigated to another page). diff --git a/chrome/browser/views/blocked_popup_container.cc b/chrome/browser/views/blocked_popup_container.cc index c6db1c6..82b9590 100644 --- a/chrome/browser/views/blocked_popup_container.cc +++ b/chrome/browser/views/blocked_popup_container.cc @@ -179,12 +179,26 @@ void BlockedPopupContainerView::ButtonPressed(views::Button* sender) { launch_menu_.reset(new Menu(this, Menu::TOPLEFT, container_->GetNativeView())); - int item_count = container_->GetTabContentsCount(); - for (int i = 0; i < item_count; ++i) { - std::wstring label = container_->GetDisplayStringForItem(i); + // Set items 1 .. popup_count as individual popups. + int popup_count = container_->GetBlockedPopupCount(); + for (int i = 0; i < popup_count; ++i) { + std::wstring url, title; + container_->GetURLAndTitleForPopup(i, &url, &title); // We can't just use the index into container_ here because Menu reserves // the value 0 as the nop command. - launch_menu_->AppendMenuItem(i + 1, label, Menu::NORMAL); + launch_menu_->AppendMenuItem(i + 1, + l10n_util::GetStringF(IDS_POPUP_TITLE_FORMAT, url, title), + Menu::NORMAL); + } + + // Set items (kImpossibleNumberOfPopups + 1) .. + // (kImpossibleNumberOfPopups + 1 + hosts.size()) as hosts. + std::vector<std::wstring> hosts(container_->GetHosts()); + if (!hosts.empty() && (popup_count > 0)) + launch_menu_->AppendSeparator(); + for (size_t i = 0; i < hosts.size(); ++i) { + launch_menu_->AppendMenuItem(kImpossibleNumberOfPopups + i + 1, + l10n_util::GetStringF(IDS_POPUP_HOST_FORMAT, hosts[i]), Menu::NORMAL); } launch_menu_->AppendSeparator(); @@ -198,7 +212,7 @@ void BlockedPopupContainerView::ButtonPressed(views::Button* sender) { launch_menu_->RunMenuAt(cursor_position.x, cursor_position.y); } else if (sender == close_button_) { container_->set_dismissed(); - container_->CloseAllPopups(); + container_->CloseAll(); } } @@ -206,15 +220,20 @@ bool BlockedPopupContainerView::IsItemChecked(int id) const { if (id == kNotifyMenuItem) return container_->GetShowBlockedPopupNotification(); + if (id > kImpossibleNumberOfPopups) + return container_->IsHostWhitelisted(id - kImpossibleNumberOfPopups - 1); + return false; } void BlockedPopupContainerView::ExecuteCommand(int id) { if (id == kNotifyMenuItem) { container_->ToggleBlockedPopupNotification(); - } else { + } else if (id > kImpossibleNumberOfPopups) { // Decrement id since all index based commands have 1 added to them. (See // ButtonPressed() for detail). + container_->ToggleWhitelistingForHost(id - kImpossibleNumberOfPopups - 1); + } else { container_->LaunchPopupIndex(id - 1); } } @@ -252,70 +271,127 @@ bool BlockedPopupContainer::GetShowBlockedPopupNotification() { } void BlockedPopupContainer::AddTabContents(TabContents* blocked_contents, - const gfx::Rect& bounds) { + const gfx::Rect& bounds, + const std::string& host) { if (has_been_dismissed_) { // We simply bounce this popup without notice. delete blocked_contents; return; } - if (blocked_popups_.size() > kImpossibleNumberOfPopups) { + if (blocked_popups_.size() >= kImpossibleNumberOfPopups) { delete blocked_contents; - LOG(INFO) << "Warning: Renderer is sending more popups to us then should be" + LOG(INFO) << "Warning: Renderer is sending more popups to us than should be" " possible. Renderer compromised?"; return; } blocked_contents->set_delegate(this); - blocked_popups_.push_back(std::make_pair(blocked_contents, bounds)); - container_view_->UpdatePopupCountLabel(); + blocked_popups_.push_back(BlockedPopup(blocked_contents, bounds, host)); + + PopupHosts::iterator i(popup_hosts_.find(host)); + if (i == popup_hosts_.end()) + popup_hosts_[host] = false; + else + DCHECK(!i->second); // This host was already reported as whitelisted! + container_view_->UpdatePopupCountLabel(); ShowSelf(); } -void BlockedPopupContainer::LaunchPopupIndex(int index) { - if (static_cast<size_t>(index) < blocked_popups_.size()) { - TabContents* contents = blocked_popups_[index].first; - gfx::Rect bounds = blocked_popups_[index].second; - blocked_popups_.erase(blocked_popups_.begin() + index); - container_view_->UpdatePopupCountLabel(); - - contents->set_delegate(NULL); - contents->DisassociateFromPopupCount(); - - // Pass this TabContents back to our owner, forcing the window to be - // displayed since user_gesture is true. - owner_->AddNewContents(contents, NEW_POPUP, bounds, true, GURL()); +void BlockedPopupContainer::OnPopupOpenedFromWhitelistedHost( + const std::string& host) { + if (has_been_dismissed_) + return; + + PopupHosts::const_iterator i(popup_hosts_.find(host)); + if (i == popup_hosts_.end()) { + popup_hosts_[host] = true; + ShowSelf(); + } else { + DCHECK(i->second); // This host was already reported as not whitelisted! } +} + +void BlockedPopupContainer::LaunchPopupIndex(int index) { + if (static_cast<size_t>(index) >= blocked_popups_.size()) + return; + + BlockedPopups::iterator i(blocked_popups_.begin() + index); + TabContents* contents = i->tab_contents; + gfx::Rect bounds(i->bounds); + EraseHostIfNeeded(i); + blocked_popups_.erase(i); + + contents->set_delegate(NULL); + contents->DisassociateFromPopupCount(); + + // Pass this TabContents back to our owner, forcing the window to be + // displayed since user_gesture is true. + owner_->AddNewContents(contents, NEW_POPUP, bounds, true, GURL()); - if (blocked_popups_.size() == 0) - CloseAllPopups(); + container_view_->UpdatePopupCountLabel(); + if (blocked_popups_.empty() && popup_hosts_.empty()) + HideSelf(); } -int BlockedPopupContainer::GetTabContentsCount() const { +int BlockedPopupContainer::GetBlockedPopupCount() const { return blocked_popups_.size(); } -std::wstring BlockedPopupContainer::GetDisplayStringForItem(int index) { - const GURL& url = blocked_popups_[index].first->GetURL().GetOrigin(); +void BlockedPopupContainer::GetURLAndTitleForPopup(int index, + std::wstring* url, + std::wstring* title) const { + DCHECK(url); + DCHECK(title); + TabContents* tab_contents = blocked_popups_[index].tab_contents; + const GURL& tab_contents_url = tab_contents->GetURL().GetOrigin(); + *url = UTF8ToWide(tab_contents_url.possibly_invalid_spec()); + *title = UTF16ToWideHack(tab_contents->GetTitle()); +} - std::wstring label = l10n_util::GetStringF( - IDS_POPUP_TITLE_FORMAT, - UTF8ToWide(url.possibly_invalid_spec()), - UTF16ToWideHack(blocked_popups_[index].first->GetTitle())); - return label; +std::vector<std::wstring> BlockedPopupContainer::GetHosts() const { + std::vector<std::wstring> hosts; + for (PopupHosts::const_iterator i(popup_hosts_.begin()); + i != popup_hosts_.end(); ++i) + hosts.push_back(UTF8ToWide(i->first)); + return hosts; } -void BlockedPopupContainer::CloseAllPopups() { - CloseEachTabContents(); - owner_->PopupNotificationVisibilityChanged(false); - container_view_->UpdatePopupCountLabel(); +bool BlockedPopupContainer::IsHostWhitelisted(int index) const { + PopupHosts::const_iterator i(ConvertHostIndexToIterator(index)); + return (i == popup_hosts_.end()) ? false : i->second; +} + +void BlockedPopupContainer::ToggleWhitelistingForHost(int index) { + PopupHosts::const_iterator i(ConvertHostIndexToIterator(index)); + const std::string& host = i->first; + bool should_whitelist = !i->second; + owner_->SetWhitelistForHost(host, should_whitelist); + if (should_whitelist) { + for (int j = blocked_popups_.size() - 1; j >= 0; --j) { + if (blocked_popups_[j].host == host) + LaunchPopupIndex(j); + } + } else { + // TODO(pkasting): Should we have some kind of handle to the open popups, so + // we can hide them all here? + popup_hosts_.erase(host); // Can't use |i| because it's a const_iterator. + if (blocked_popups_.empty() && popup_hosts_.empty()) + HideSelf(); + } + // At this point i is invalid, since the item it points to was deleted (on + // both conditional arms). +} + +void BlockedPopupContainer::CloseAll() { + ClearData(); HideSelf(); } // Overridden from ConstrainedWindow: void BlockedPopupContainer::CloseConstrainedWindow() { - CloseEachTabContents(); + ClearData(); // Broadcast to all observers of NOTIFY_CWINDOW_CLOSED. // One example of such an observer is AutomationCWindowTracker in the @@ -335,7 +411,7 @@ void BlockedPopupContainer::RepositionConstrainedWindowTo( std::wstring BlockedPopupContainer::GetWindowTitle() const { return l10n_util::GetStringF(IDS_POPUPS_BLOCKED_COUNT, - IntToWString(GetTabContentsCount())); + IntToWString(GetBlockedPopupCount())); } const gfx::Rect& BlockedPopupContainer::GetCurrentBounds() const { @@ -361,25 +437,27 @@ void BlockedPopupContainer::AddNewContents(TabContents* source, } void BlockedPopupContainer::CloseContents(TabContents* source) { - for (std::vector<std::pair<TabContents*, gfx::Rect> >::iterator it = - blocked_popups_.begin(); it != blocked_popups_.end(); ++it) { - if (it->first == source) { - it->first->set_delegate(NULL); + for (BlockedPopups::iterator it = blocked_popups_.begin(); + it != blocked_popups_.end(); ++it) { + if (it->tab_contents == source) { + it->tab_contents->set_delegate(NULL); + EraseHostIfNeeded(it); blocked_popups_.erase(it); + container_view_->UpdatePopupCountLabel(); break; } } - if (blocked_popups_.size() == 0) - CloseAllPopups(); + if (blocked_popups_.empty()) + HideSelf(); } void BlockedPopupContainer::MoveContents(TabContents* source, - const gfx::Rect& position) { - for (std::vector<std::pair<TabContents*, gfx::Rect> >::iterator it = - blocked_popups_.begin(); it != blocked_popups_.end(); ++it) { - if (it->first == source) { - it->second = position; + 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; } } @@ -402,18 +480,14 @@ ExtensionFunctionDispatcher* BlockedPopupContainer:: // Overridden from Animation: void BlockedPopupContainer::AnimateToState(double state) { - if (in_show_animation_) - visibility_percentage_ = state; - else - visibility_percentage_ = 1 - state; - + visibility_percentage_ = in_show_animation_ ? state : (1 - state); SetPosition(); } // Override from views::WidgetWin: void BlockedPopupContainer::OnFinalMessage(HWND window) { owner_->WillClose(this); - CloseEachTabContents(); + ClearData(); WidgetWin::OnFinalMessage(window); } @@ -449,6 +523,7 @@ void BlockedPopupContainer::HideSelf() { in_show_animation_ = false; Animation::SetDuration(kHideAnimationDurationMS); Animation::Start(); + owner_->PopupNotificationVisibilityChanged(false); } void BlockedPopupContainer::ShowSelf() { @@ -458,6 +533,7 @@ void BlockedPopupContainer::ShowSelf() { Animation::SetDuration(kShowAnimationDurationMS); Animation::Start(); } + owner_->PopupNotificationVisibilityChanged(true); } void BlockedPopupContainer::SetPosition() { @@ -481,12 +557,37 @@ void BlockedPopupContainer::SetPosition() { } } -void BlockedPopupContainer::CloseEachTabContents() { - while (!blocked_popups_.empty()) { - blocked_popups_.back().first->set_delegate(NULL); - delete blocked_popups_.back().first; - blocked_popups_.pop_back(); +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(); + popup_hosts_.clear(); +} + +BlockedPopupContainer::PopupHosts::const_iterator + BlockedPopupContainer::ConvertHostIndexToIterator(int index) const { + if (static_cast<size_t>(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 (int j = 0; j < index; ++j) + ++i; + return i; +} + +void BlockedPopupContainer::EraseHostIfNeeded(BlockedPopups::iterator i) { + const std::string& host = i->host; + if (host.empty()) + return; + for (BlockedPopups::const_iterator j(blocked_popups_.begin()); + j != blocked_popups_.end(); ++j) { + if ((j != i) && (j->host == host)) + return; + } + popup_hosts_.erase(host); } diff --git a/chrome/browser/views/blocked_popup_container.h b/chrome/browser/views/blocked_popup_container.h index 214b8f8..80112e5 100644 --- a/chrome/browser/views/blocked_popup_container.h +++ b/chrome/browser/views/blocked_popup_container.h @@ -104,19 +104,39 @@ class BlockedPopupContainer : public ConstrainedWindow, // Adds a Tabbed contents to this container. |bounds| are the window bounds // requested by the popup window. - void AddTabContents(TabContents* blocked_contents, const gfx::Rect& bounds); + void AddTabContents(TabContents* blocked_contents, + const gfx::Rect& bounds, + const std::string& host); + + // Called when a popup from whitelisted host |host| is opened, so we can show + // the "stop whitelisting" UI. + void OnPopupOpenedFromWhitelistedHost(const std::string& host); // Creates a window from blocked popup |index|. void LaunchPopupIndex(int index); // Returns the number of blocked popups - int GetTabContentsCount() const; + int GetBlockedPopupCount() const; + + // Returns the URL and title for popup |index|, used to construct a string for + // display. + void GetURLAndTitleForPopup(int index, + std::wstring* url, + std::wstring* title) const; + + // 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(int index) const; - // Returns the string to display to the user in the menu for item |index|. - std::wstring GetDisplayStringForItem(int index); + // If host |index| is currently whitelisted, un-whitelists it. Otherwise, + // whitelists it and opens all blocked popups from it. + void ToggleWhitelistingForHost(int index); // Deletes all popups and hides the interface parts. - void CloseAllPopups(); + void CloseAll(); // Called to force this container to never show itself again. void set_dismissed() { has_been_dismissed_ = true; } @@ -168,7 +188,7 @@ class BlockedPopupContainer : public ConstrainedWindow, virtual void CloseContents(TabContents* source); // Changes the opening rectangle associated with |source|. - virtual void MoveContents(TabContents* source, const gfx::Rect& pos); + virtual void MoveContents(TabContents* source, const gfx::Rect& new_bounds); // Always returns true. virtual bool IsPopup(TabContents* source); @@ -207,6 +227,22 @@ class BlockedPopupContainer : public ConstrainedWindow, virtual void OnSize(UINT param, const CSize& size); 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; + + // string is hostname. bool is whitelisted status. + typedef std::map<std::string, bool> PopupHosts; + // Creates a container for a certain TabContents. BlockedPopupContainer(TabContents* owner, Profile* profile); @@ -225,14 +261,26 @@ class BlockedPopupContainer : public ConstrainedWindow, // change. void SetPosition(); - // Deletes each contents in |blocked_popups_|. - void CloseEachTabContents(); + // 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(int index) const; + + // If the popup at |i| is the last one associated with its host, removes the + // host from the host list. + void EraseHostIfNeeded(BlockedPopups::iterator i); // The TabContents that owns and constrains this BlockedPopupContainer. TabContents* owner_; - // The TabContents and initial positions of all blocked popups. - std::vector<std::pair<TabContents*, gfx::Rect> > blocked_popups_; + // Information about all blocked popups. + BlockedPopups blocked_popups_; + + // Information about all popup hosts. + PopupHosts popup_hosts_; // Our associated view object. BlockedPopupContainerView* container_view_; diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h index a74e54b..fe12745f 100644 --- a/chrome/common/render_messages_internal.h +++ b/chrome/common/render_messages_internal.h @@ -496,7 +496,7 @@ IPC_BEGIN_MESSAGES(View) // Sent by the Browser process to alert a window about whether a blocked // popup notification is visible. The renderer assumes every new window is a // blocked popup until notified otherwise. - IPC_MESSAGE_ROUTED1(ViewMsg_PopupNotificationVisiblityChanged, + IPC_MESSAGE_ROUTED1(ViewMsg_PopupNotificationVisibilityChanged, bool /* Whether it is visible */) // Sent by AudioRendererHost to renderer to request an audio packet. diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc index d173537..03df749 100644 --- a/chrome/renderer/render_view.cc +++ b/chrome/renderer/render_view.cc @@ -418,8 +418,8 @@ void RenderView::OnMessageReceived(const IPC::Message& message) { OnDisassociateFromPopupCount) IPC_MESSAGE_HANDLER(ViewMsg_AutofillSuggestions, OnReceivedAutofillSuggestions) - IPC_MESSAGE_HANDLER(ViewMsg_PopupNotificationVisiblityChanged, - OnPopupNotificationVisiblityChanged) + IPC_MESSAGE_HANDLER(ViewMsg_PopupNotificationVisibilityChanged, + OnPopupNotificationVisibilityChanged) IPC_MESSAGE_HANDLER(ViewMsg_MoveOrResizeStarted, OnMoveOrResizeStarted) IPC_MESSAGE_HANDLER(ViewMsg_ExtensionResponse, OnExtensionResponse) IPC_MESSAGE_HANDLER(ViewMsg_ClearFocusedNode, OnClearFocusedNode) @@ -1698,7 +1698,7 @@ void RenderView::OnReceivedAutofillSuggestions( default_suggestion_index); } -void RenderView::OnPopupNotificationVisiblityChanged(bool visible) { +void RenderView::OnPopupNotificationVisibilityChanged(bool visible) { popup_notification_visible_ = visible; } @@ -1956,7 +1956,7 @@ void RenderView::Show(WebWidget* webwidget, WindowOpenDisposition disposition) { } void RenderView::CloseWidgetSoon(WebWidget* webwidget) { - if (popup_notification_visible_ == false) + if (!popup_notification_visible_) RenderWidget::CloseWidgetSoon(webwidget); } diff --git a/chrome/renderer/render_view.h b/chrome/renderer/render_view.h index 8c34769..bdd415c 100644 --- a/chrome/renderer/render_view.h +++ b/chrome/renderer/render_view.h @@ -557,7 +557,7 @@ class RenderView : public RenderWidget, int default_suggestions_index); // Message that the popup notification has been shown or hidden. - void OnPopupNotificationVisiblityChanged(bool visible); + void OnPopupNotificationVisibilityChanged(bool visible); // Handles messages posted from automation. void OnMessageFromExternalHost(const std::string& message, @@ -765,7 +765,7 @@ class RenderView : public RenderWidget, // We need to prevent windows from closing themselves with a window.close() // call while a blocked popup notification is being displayed. We cannot - // synchronously querry the Browser process. We cannot wait for the Browser + // synchronously query the Browser process. We cannot wait for the Browser // process to send a message to us saying that a blocked popup notification // is being displayed. We instead assume that when we create a window off // this RenderView, that it is going to be blocked until we get a message |