blob: 30752fa0229562ba7dc4e794dc01b74b8cdc57ba [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/extensions/extension_install_prompt_show_params.h"
#include <memory>
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "chrome/browser/profiles/profile.h"
#include "content/public/browser/web_contents.h"
#if !BUILDFLAG(IS_ANDROID)
#include "ui/native_window_tracker/native_window_tracker.h"
#endif
#if defined(USE_AURA)
#include "ui/aura/window.h"
#endif
namespace {
#if defined(USE_AURA)
bool g_root_checking_enabled = true;
#endif
bool RootCheck(gfx::NativeWindow window) {
#if defined(USE_AURA)
// If the window is not contained in a root window, then it's not connected
// to a display and can't be used as the context. To do otherwise results in
// checks later on assuming context has a root.
return !g_root_checking_enabled || (window->GetRootWindow() != nullptr);
#else
return true;
#endif
}
} // namespace
ExtensionInstallPromptShowParams::ExtensionInstallPromptShowParams(
content::WebContents* contents)
: profile_(Profile::FromBrowserContext(contents->GetBrowserContext())),
parent_web_contents_(contents->GetWeakPtr()) {
DCHECK(profile_);
DCHECK(parent_web_contents_);
if (!parent_web_contents_->GetTopLevelNativeWindow()) {
// WebContents were created without a top-level window. This can happen when
// the callers pass a dummy WebContents, or in some tests. There is no
// window to track in this case. Reset the WebContents pointer and just keep
// the profile. If we keep web contents in this case, WasParentDestroyed()
// will always return true, even though there is no real window to check.
parent_web_contents_.reset();
}
}
ExtensionInstallPromptShowParams::ExtensionInstallPromptShowParams(
Profile* profile,
gfx::NativeWindow parent_window)
: profile_(profile),
parent_web_contents_(nullptr),
parent_window_(parent_window) {
DCHECK(profile);
#if BUILDFLAG(IS_ANDROID)
DCHECK(!parent_window) << "Android does not support a parent window.";
#else
if (parent_window_) {
native_window_tracker_ = ui::NativeWindowTracker::Create(parent_window_);
}
#endif
}
ExtensionInstallPromptShowParams::~ExtensionInstallPromptShowParams() = default;
content::WebContents* ExtensionInstallPromptShowParams::GetParentWebContents() {
return parent_web_contents_.get();
}
gfx::NativeWindow ExtensionInstallPromptShowParams::GetParentWindow() {
if (WasParentDestroyed()) {
return gfx::NativeWindow();
}
if (WasConfiguredForWebContents()) {
return parent_web_contents_->GetTopLevelNativeWindow();
}
return parent_window_;
}
bool ExtensionInstallPromptShowParams::WasParentDestroyed() {
if (profile_->ShutdownStarted()) {
return true;
}
if (WasConfiguredForWebContents()) {
return !parent_web_contents_ || parent_web_contents_->IsBeingDestroyed() ||
!parent_web_contents_->GetTopLevelNativeWindow() ||
!RootCheck(parent_web_contents_->GetTopLevelNativeWindow());
}
#if !BUILDFLAG(IS_ANDROID)
if (native_window_tracker_) {
return native_window_tracker_->WasNativeWindowDestroyed() ||
!RootCheck(parent_window_);
}
#endif
return false;
}
bool ExtensionInstallPromptShowParams::WasConfiguredForWebContents() {
// If we ever had a valid web contents, it means we were configured for it.
return parent_web_contents_ || parent_web_contents_.WasInvalidated();
}
namespace test {
ScopedDisableRootChecking::ScopedDisableRootChecking() {
#if defined(USE_AURA)
// There should be no need to support multiple ScopedDisableRootCheckings
// at a time.
DCHECK(g_root_checking_enabled);
g_root_checking_enabled = false;
#endif
}
ScopedDisableRootChecking::~ScopedDisableRootChecking() {
#if defined(USE_AURA)
DCHECK(!g_root_checking_enabled);
g_root_checking_enabled = true;
#endif
}
} // namespace test