blob: 24fb87fe52b9d85e4fb35f1739e846ada878247f [file] [log] [blame]
// Copyright 2014 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/ui/blocked_content/popunder_preventer.h"
#include <set>
#include "base/stl_util.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_delegate.h"
#include "extensions/buildflags/buildflags.h"
#if BUILDFLAG(ENABLE_EXTENSIONS)
#include "components/guest_view/browser/guest_view_base.h"
#endif
namespace {
using WebContentsSet = std::set<content::WebContents*>;
WebContentsSet BuildOpenerSet(content::WebContents* contents) {
WebContentsSet result;
while (contents) {
result.insert(contents);
contents = content::WebContents::FromRenderFrameHost(
contents->GetOriginalOpener());
}
return result;
}
} // namespace
PopunderPreventer::PopunderPreventer(content::WebContents* activating_contents)
: popup_(nullptr) {
// If a popup is the active window, and the WebContents that is going to be
// activated shares in the opener chain of that popup, then we suspect that
// WebContents to be trying to create a popunder. Store the popup window so
// that it can be re-activated once the dialog (or whatever is causing the
// activation) is closed.
Browser* active_browser = BrowserList::GetInstance()->GetLastActive();
if (!active_browser || !active_browser->is_type_popup())
return;
content::WebContents* active_popup =
active_browser->tab_strip_model()->GetActiveWebContents();
if (!active_popup)
return;
content::WebContents* actual_activating_contents = activating_contents;
#if BUILDFLAG(ENABLE_EXTENSIONS)
// If the dialog was triggered via an PDF, get the actual web contents that
// embeds the PDF.
guest_view::GuestViewBase* guest =
guest_view::GuestViewBase::FromWebContents(activating_contents);
if (guest)
actual_activating_contents = guest->embedder_web_contents();
#endif
WebContentsSet popup_opener_set = BuildOpenerSet(active_popup);
WebContentsSet activator_opener_set =
BuildOpenerSet(actual_activating_contents);
WebContentsSet common_openers = base::STLSetIntersection<WebContentsSet>(
popup_opener_set, activator_opener_set);
if (!common_openers.empty()) {
// The popup is indeed related to the WebContents wanting to activate. Store
// it, so we can focus it later.
popup_ = active_popup;
Observe(popup_);
}
}
PopunderPreventer::~PopunderPreventer() {
if (!popup_)
return;
content::WebContentsDelegate* delegate = popup_->GetDelegate();
if (!delegate)
return;
delegate->ActivateContents(popup_);
}
void PopunderPreventer::WebContentsDestroyed() {
popup_ = nullptr;
}