1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/ui/blocked_content/popup_blocker_tab_helper.h"
7 #include "chrome/browser/chrome_notification_types.h"
8 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
9 #include "chrome/browser/content_settings/tab_specific_content_settings.h"
10 #include "chrome/browser/profiles/profile.h"
11 #include "chrome/browser/ui/blocked_content/blocked_window_params.h"
12 #include "chrome/browser/ui/browser_navigator.h"
13 #include "chrome/browser/ui/tabs/tab_strip_model.h"
14 #include "chrome/common/render_messages.h"
15 #include "components/content_settings/core/browser/host_content_settings_map.h"
16 #include "content/public/browser/navigation_controller.h"
17 #include "content/public/browser/navigation_details.h"
18 #include "content/public/browser/navigation_entry.h"
19 #include "content/public/browser/render_view_host.h"
20 #include "content/public/browser/web_contents.h"
21 #include "content/public/browser/web_contents_delegate.h"
22 #include "third_party/WebKit/public/web/WebWindowFeatures.h"
24 #if defined(OS_ANDROID)
25 #include "chrome/browser/ui/android/tab_model/tab_model_list.h"
28 using blink::WebWindowFeatures
;
30 const size_t kMaximumNumberOfPopups
= 25;
32 DEFINE_WEB_CONTENTS_USER_DATA_KEY(PopupBlockerTabHelper
);
34 struct PopupBlockerTabHelper::BlockedRequest
{
35 BlockedRequest(const chrome::NavigateParams
& params
,
36 const WebWindowFeatures
& window_features
)
37 : params(params
), window_features(window_features
) {}
39 chrome::NavigateParams params
;
40 WebWindowFeatures window_features
;
43 PopupBlockerTabHelper::PopupBlockerTabHelper(
44 content::WebContents
* web_contents
)
45 : content::WebContentsObserver(web_contents
) {
48 PopupBlockerTabHelper::~PopupBlockerTabHelper() {
51 void PopupBlockerTabHelper::DidNavigateMainFrame(
52 const content::LoadCommittedDetails
& details
,
53 const content::FrameNavigateParams
& params
) {
54 // Clear all page actions, blocked content notifications and browser actions
55 // for this tab, unless this is an in-page navigation.
56 if (details
.is_in_page
)
59 // Close blocked popups.
60 if (!blocked_popups_
.IsEmpty()) {
61 blocked_popups_
.Clear();
62 PopupNotificationVisibilityChanged(false);
66 void PopupBlockerTabHelper::PopupNotificationVisibilityChanged(
68 if (!web_contents()->IsBeingDestroyed()) {
69 TabSpecificContentSettings::FromWebContents(web_contents())->
70 SetPopupsBlocked(visible
);
74 bool PopupBlockerTabHelper::MaybeBlockPopup(
75 const chrome::NavigateParams
& params
,
76 const WebWindowFeatures
& window_features
) {
77 // A page can't spawn popups (or do anything else, either) until its load
78 // commits, so when we reach here, the popup was spawned by the
79 // NavigationController's last committed entry, not the active entry. For
80 // example, if a page opens a popup in an onunload() handler, then the active
81 // entry is the page to be loaded as we navigate away from the unloading
82 // page. For this reason, we can't use GetURL() to get the opener URL,
83 // because it returns the active entry.
84 content::NavigationEntry
* entry
=
85 web_contents()->GetController().GetLastCommittedEntry();
86 GURL creator
= entry
? entry
->GetVirtualURL() : GURL();
88 Profile::FromBrowserContext(web_contents()->GetBrowserContext());
90 if (creator
.is_valid() &&
91 HostContentSettingsMapFactory::GetForProfile(profile
)->GetContentSetting(
92 creator
, creator
, CONTENT_SETTINGS_TYPE_POPUPS
, std::string()) ==
93 CONTENT_SETTING_ALLOW
) {
96 if (blocked_popups_
.size() < kMaximumNumberOfPopups
) {
97 blocked_popups_
.Add(new BlockedRequest(params
, window_features
));
98 TabSpecificContentSettings::FromWebContents(web_contents())->
99 OnContentBlocked(CONTENT_SETTINGS_TYPE_POPUPS
);
105 void PopupBlockerTabHelper::AddBlockedPopup(const BlockedWindowParams
& params
) {
106 chrome::NavigateParams nav_params
=
107 params
.CreateNavigateParams(web_contents());
109 if (blocked_popups_
.size() < kMaximumNumberOfPopups
) {
110 blocked_popups_
.Add(new BlockedRequest(nav_params
, params
.features()));
111 TabSpecificContentSettings::FromWebContents(web_contents())->
112 OnContentBlocked(CONTENT_SETTINGS_TYPE_POPUPS
);
116 void PopupBlockerTabHelper::ShowBlockedPopup(int32 id
) {
117 BlockedRequest
* popup
= blocked_popups_
.Lookup(id
);
120 // We set user_gesture to true here, so the new popup gets correctly focused.
121 popup
->params
.user_gesture
= true;
122 #if defined(OS_ANDROID)
123 TabModelList::HandlePopupNavigation(&popup
->params
);
125 chrome::Navigate(&popup
->params
);
127 if (popup
->params
.target_contents
) {
128 popup
->params
.target_contents
->Send(new ChromeViewMsg_SetWindowFeatures(
129 popup
->params
.target_contents
->GetRoutingID(), popup
->window_features
));
131 blocked_popups_
.Remove(id
);
132 if (blocked_popups_
.IsEmpty())
133 PopupNotificationVisibilityChanged(false);
136 size_t PopupBlockerTabHelper::GetBlockedPopupsCount() const {
137 return blocked_popups_
.size();
140 PopupBlockerTabHelper::PopupIdMap
141 PopupBlockerTabHelper::GetBlockedPopupRequests() {
143 for (IDMap
<BlockedRequest
, IDMapOwnPointer
>::const_iterator
iter(
147 result
[iter
.GetCurrentKey()] = iter
.GetCurrentValue()->params
.url
;