blob: 107f75833f11b191056abf7770dc7c9535ff86ab [file] [log] [blame]
// Copyright 2013 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_view_host_factory.h"
#include <string>
#include "base/notimplemented.h"
#include "chrome/browser/extensions/browser_extension_window_controller.h"
#include "chrome/browser/extensions/extension_view_host.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/browser_window/public/browser_window_features.h"
#include "chrome/common/url_constants.h"
#include "content/public/browser/keyboard_event_processing_result.h"
#include "content/public/browser/web_contents.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/extension_util.h"
#include "extensions/common/manifest_handlers/incognito_info.h"
#include "extensions/common/mojom/view_type.mojom.h"
#if !BUILDFLAG(IS_ANDROID)
#include "chrome/browser/ui/browser.h"
#endif // !BUILDFLAG(IS_ANDROID)
namespace extensions {
namespace {
#if BUILDFLAG(IS_ANDROID)
// Delegate for ExtensionViewHost on Android.
class ExtensionViewHostDelegateAndroid : public ExtensionViewHost::Delegate {
public:
ExtensionViewHostDelegateAndroid() = default;
ExtensionViewHostDelegateAndroid(const ExtensionViewHostDelegateAndroid&) =
delete;
ExtensionViewHostDelegateAndroid& operator=(
const ExtensionViewHostDelegateAndroid&) = delete;
~ExtensionViewHostDelegateAndroid() override = default;
content::WebContents* OpenURL(
const content::OpenURLParams& params,
base::OnceCallback<void(content::NavigationHandle&)>
navigation_handle_callback) override {
// TODO(cbrug.com/385987224): Implement this method for Android.
NOTIMPLEMENTED();
return nullptr;
}
content::KeyboardEventProcessingResult PreHandleKeyboardEvent(
content::WebContents* source,
const input::NativeWebKeyboardEvent& event) override {
// TODO(cbrug.com/385987224): Implement this method for Android.
NOTIMPLEMENTED();
return content::KeyboardEventProcessingResult::NOT_HANDLED;
}
std::unique_ptr<content::EyeDropper> OpenEyeDropper(
content::RenderFrameHost* frame,
content::EyeDropperListener* listener) override {
// TODO(cbrug.com/385987224): Implement this method for Android.
NOTIMPLEMENTED();
return nullptr;
}
WindowController* GetExtensionWindowController() const override {
// TODO(cbrug.com/385987224): Implement this method for Android.
NOTIMPLEMENTED();
return nullptr;
}
};
#else // BUILDFLAG(IS_ANDROID)
// Delegate for ExtensionViewHost attached to a specific browser window.
class ExtensionViewHostBrowserDelegate : public ExtensionViewHost::Delegate {
public:
explicit ExtensionViewHostBrowserDelegate(Browser* browser)
: browser_(browser) {
DCHECK(browser_);
}
ExtensionViewHostBrowserDelegate(const ExtensionViewHostBrowserDelegate&) =
delete;
ExtensionViewHostBrowserDelegate& operator=(
const ExtensionViewHostBrowserDelegate&) = delete;
~ExtensionViewHostBrowserDelegate() override = default;
content::WebContents* OpenURL(
const content::OpenURLParams& params,
base::OnceCallback<void(content::NavigationHandle&)>
navigation_handle_callback) override {
return browser_->OpenURL(params, std::move(navigation_handle_callback));
}
content::KeyboardEventProcessingResult PreHandleKeyboardEvent(
content::WebContents* source,
const input::NativeWebKeyboardEvent& event) override {
return browser_->PreHandleKeyboardEvent(source, event);
}
std::unique_ptr<content::EyeDropper> OpenEyeDropper(
content::RenderFrameHost* frame,
content::EyeDropperListener* listener) override {
return browser_->OpenEyeDropper(frame, listener);
}
WindowController* GetExtensionWindowController() const override {
return BrowserExtensionWindowController::From(browser_);
}
private:
raw_ptr<Browser> browser_;
};
// Delegate for ExtensionViewHost attached to a specific tab.
class ExtensionViewHostTabDelegate : public ExtensionViewHost::Delegate {
public:
explicit ExtensionViewHostTabDelegate(content::WebContents* web_contents)
: web_contents_(web_contents) {
DCHECK(web_contents_);
}
ExtensionViewHostTabDelegate(const ExtensionViewHostTabDelegate&) = delete;
ExtensionViewHostTabDelegate& operator=(const ExtensionViewHostTabDelegate&) =
delete;
~ExtensionViewHostTabDelegate() override = default;
content::WebContents* OpenURL(
const content::OpenURLParams& params,
base::OnceCallback<void(content::NavigationHandle&)>
navigation_handle_callback) override {
Browser* browser = FindBrowser();
if (browser == nullptr) {
return nullptr;
}
return browser->OpenURL(params, std::move(navigation_handle_callback));
}
content::KeyboardEventProcessingResult PreHandleKeyboardEvent(
content::WebContents* source,
const input::NativeWebKeyboardEvent& event) override {
Browser* browser = FindBrowser();
if (browser == nullptr) {
return content::KeyboardEventProcessingResult::NOT_HANDLED;
}
return browser->PreHandleKeyboardEvent(source, event);
}
std::unique_ptr<content::EyeDropper> OpenEyeDropper(
content::RenderFrameHost* frame,
content::EyeDropperListener* listener) override {
Browser* browser = FindBrowser();
if (browser == nullptr) {
return nullptr;
}
return browser->OpenEyeDropper(frame, listener);
}
WindowController* GetExtensionWindowController() const override {
Browser* browser = FindBrowser();
if (browser == nullptr) {
return nullptr;
}
return BrowserExtensionWindowController::From(browser);
}
private:
Browser* FindBrowser() const {
return chrome::FindBrowserWithTab(web_contents_);
}
raw_ptr<content::WebContents> web_contents_;
};
#endif // BUILDFLAG(IS_ANDROID)
// Creates a new ExtensionHost with its associated view, grouping it in the
// appropriate SiteInstance (and therefore process) based on the URL and
// profile.
std::unique_ptr<ExtensionViewHost> CreateViewHostForExtension(
const Extension* extension,
const GURL& url,
Profile* profile,
mojom::ViewType view_type,
std::unique_ptr<ExtensionViewHost::Delegate> delegate) {
DCHECK(profile);
return std::make_unique<ExtensionViewHost>(extension, profile, url, view_type,
std::move(delegate));
}
// Creates a view host for an extension in an incognito window. Returns NULL
// if the extension is not allowed to run in incognito.
std::unique_ptr<ExtensionViewHost> CreateViewHostForIncognito(
const Extension* extension,
const GURL& url,
Profile* profile,
mojom::ViewType view_type,
std::unique_ptr<ExtensionViewHost::Delegate> delegate) {
DCHECK(extension);
DCHECK(profile->IsOffTheRecord());
if (!IncognitoInfo::IsSplitMode(extension)) {
// If it's not split-mode the host is associated with the original profile.
Profile* original_profile = profile->GetOriginalProfile();
return CreateViewHostForExtension(extension, url, original_profile,
view_type, std::move(delegate));
}
// Create the host if the extension can run in incognito.
if (util::IsIncognitoEnabled(extension->id(), profile)) {
return CreateViewHostForExtension(extension, url, profile, view_type,
std::move(delegate));
}
NOTREACHED() << "We shouldn't be trying to create an incognito extension "
"view unless it has been enabled for incognito.";
}
// Returns the extension associated with |url| in |profile|. Returns NULL if
// the extension does not exist.
const Extension* GetExtensionForUrl(Profile* profile, const GURL& url) {
ExtensionRegistry* registry = ExtensionRegistry::Get(profile);
if (!registry)
return nullptr;
std::string extension_id = url.host();
return registry->enabled_extensions().GetByID(extension_id);
}
std::unique_ptr<ExtensionViewHost> CreateExtensionViewHost(
const Extension& extension,
const GURL& url,
Profile* profile,
extensions::mojom::ViewType view_type,
std::unique_ptr<ExtensionViewHost::Delegate> delegate) {
CHECK(profile);
if (profile->IsOffTheRecord()) {
return CreateViewHostForIncognito(&extension, url, profile, view_type,
std::move(delegate));
}
return CreateViewHostForExtension(&extension, url, profile, view_type,
std::move(delegate));
}
// Creates and initializes an ExtensionViewHost for the extension with |url|.
std::unique_ptr<ExtensionViewHost> CreateViewHost(
const GURL& url,
Profile* profile,
extensions::mojom::ViewType view_type,
std::unique_ptr<ExtensionViewHost::Delegate> delegate) {
CHECK(profile);
const Extension* extension = GetExtensionForUrl(profile, url);
if (!extension) {
return nullptr;
}
return CreateExtensionViewHost(*extension, url, profile, view_type,
std::move(delegate));
}
} // namespace
#if BUILDFLAG(IS_ANDROID)
// static
std::unique_ptr<ExtensionViewHost> ExtensionViewHostFactory::CreatePopupHost(
const GURL& url,
Profile* profile) {
return CreateViewHost(url, profile, mojom::ViewType::kExtensionPopup,
std::make_unique<ExtensionViewHostDelegateAndroid>());
}
#else // BUILDFLAG(IS_ANDROID)
// static
std::unique_ptr<ExtensionViewHost> ExtensionViewHostFactory::CreatePopupHost(
const GURL& url,
Browser* browser) {
DCHECK(browser);
return CreateViewHost(
url, browser->profile(), mojom::ViewType::kExtensionPopup,
std::make_unique<ExtensionViewHostBrowserDelegate>(browser));
}
// static
std::unique_ptr<ExtensionViewHost>
ExtensionViewHostFactory::CreateSidePanelHost(
const Extension& extension,
const GURL& url,
BrowserWindowInterface* browser,
tabs::TabInterface* tab_interface) {
DCHECK(browser == nullptr ^ tab_interface == nullptr);
Profile* profile =
browser ? browser->GetProfile()
: tab_interface->GetBrowserWindowInterface()->GetProfile();
std::unique_ptr<ExtensionViewHost::Delegate> delegate =
browser ? static_cast<std::unique_ptr<ExtensionViewHost::Delegate>>(
std::make_unique<ExtensionViewHostBrowserDelegate>(
browser->GetBrowserForMigrationOnly()))
: std::make_unique<ExtensionViewHostTabDelegate>(
tab_interface->GetContents());
return CreateExtensionViewHost(extension, url, profile,
mojom::ViewType::kExtensionSidePanel,
std::move(delegate));
}
#endif // BUILDFLAG(IS_ANDROID)
} // namespace extensions