blob: 1822c92ab51a78e4c636e91baf5f395ba378fae2 [file] [log] [blame]
// Copyright 2014 The Chromium Authors
// 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 "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 = contents->GetFirstWebContentsInLiveOriginalOpenerChain();
}
return result;
}
} // namespace
PopunderPreventer::PopunderPreventer(content::WebContents* activating_contents)
: activating_contents_(activating_contents->GetWeakPtr()) {
WillActivateWebContents(activating_contents);
}
PopunderPreventer::~PopunderPreventer() {
for (base::WeakPtr<content::WebContents>& popup : popups_) {
auto* browser = popup ? chrome::FindBrowserWithTab(popup.get()) : nullptr;
// Only popup, app, or app-popup browser windows are potential popunders.
if (browser && (browser->is_type_app() || browser->is_type_popup() ||
browser->is_type_app_popup())) {
browser->ActivateContents(popup.get());
}
}
}
void PopunderPreventer::WillActivateWebContents(
content::WebContents* activating_contents) {
DCHECK_EQ(activating_contents_.get(), activating_contents);
// Check if the active window may be a popunder of `activating_contents`.
if (Browser* active = BrowserList::GetInstance()->GetLastActive()) {
AddPotentialPopunder(active->tab_strip_model()->GetActiveWebContents());
}
}
void PopunderPreventer::AddPotentialPopunder(content::WebContents* popup) {
content::WebContents* top_level_activating_contents =
activating_contents_.get();
#if BUILDFLAG(ENABLE_EXTENSIONS)
// If the dialog was triggered via an PDF, get the top level web contents that
// embeds the PDF.
top_level_activating_contents =
guest_view::GuestViewBase::GetTopLevelWebContents(
top_level_activating_contents);
#endif
// Check if `popup` and `activating_contents_` share an opener chain entry.
// Ignore `activating_contents_` itself; reactivating that on destruction
// causes rentrancy, e.g. when exiting app fullscreen: crbug.com/331095620
WebContentsSet common_openers = base::STLSetIntersection<WebContentsSet>(
BuildOpenerSet(popup), BuildOpenerSet(top_level_activating_contents));
if (popup != top_level_activating_contents && !common_openers.empty()) {
// Store the suspected popunder, which should be focused later.
popups_.push_back(popup->GetWeakPtr());
}
}