summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnu Aliyas <[email protected]>2025-01-23 13:19:25 +0100
committerAnu Aliyas <[email protected]>2025-05-30 10:41:46 +0200
commit0ce053c22b86c16e82b3fd7c28956481b58500b0 (patch)
tree04012d05bf76aad0f45412c4b0421d832deeb917
parent824eb0f3f81cb754a8d70c2f24ce6387459ae7ea (diff)
Add support for extension WebUIHEADdev
The WebUI can be accessed using the URL chrome://extensions This will list all the enabled and disable extensions and also provides a means to load extensions. Change-Id: Iddd61a858d100f292f7214e53a1ea753228af0b5 Reviewed-by: Allan Sandfeld Jensen <[email protected]>
-rw-r--r--src/core/CMakeLists.txt3
-rw-r--r--src/core/configure/BUILD.root.gn.in6
-rw-r--r--src/core/content_browser_client_qt.cpp6
-rw-r--r--src/core/extensions/webui/extensions_ui_page_handler_qt.cpp70
-rw-r--r--src/core/extensions/webui/extensions_ui_page_handler_qt.h39
-rw-r--r--src/core/extensions/webui/extensions_ui_qt.cpp48
-rw-r--r--src/core/extensions/webui/extensions_ui_qt.h33
-rw-r--r--src/core/extensions/webui/select_file_dialog.cpp51
-rw-r--r--src/core/extensions/webui/select_file_dialog.h38
-rw-r--r--src/core/net/webui_controller_factory_qt.cpp22
-rw-r--r--tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp2
11 files changed, 302 insertions, 16 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 8dff712b5..b2ca49103 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -295,6 +295,9 @@ foreach(arch ${archs})
renderer/extensions/extensions_renderer_api_provider_qt.cpp renderer/extensions/extensions_renderer_api_provider_qt.h
renderer/extensions/extensions_renderer_client_qt.cpp renderer/extensions/extensions_renderer_client_qt.h
renderer/extensions/resource_request_policy_qt.cpp renderer/extensions/resource_request_policy_qt.h
+ extensions/webui/extensions_ui_page_handler_qt.cpp extensions/webui/extensions_ui_page_handler_qt.h
+ extensions/webui/extensions_ui_qt.cpp extensions/webui/extensions_ui_qt.h
+ extensions/webui/select_file_dialog.cpp extensions/webui/select_file_dialog.h
)
extend_gn_target(${buildGn} CONDITION QT_FEATURE_webengine_extensions AND QT_FEATURE_webengine_printing_and_pdf
diff --git a/src/core/configure/BUILD.root.gn.in b/src/core/configure/BUILD.root.gn.in
index 9ece7cd56..a17ecbb9c 100644
--- a/src/core/configure/BUILD.root.gn.in
+++ b/src/core/configure/BUILD.root.gn.in
@@ -439,6 +439,8 @@ source_set("qtwebengine_sources") {
"//extensions/strings",
"//qtwebengine/browser/extensions/api:api_registration",
"//qtwebengine/common/extensions/api:api",
+ "//qtwebengine/browser/extensions/webui:mojo_bindings",
+ "//qtwebengine/browser/extensions/resources",
]
sources += [
"//chrome/browser/extensions/api/streams_private/streams_private_api.cc",
@@ -455,6 +457,8 @@ source_set("qtwebengine_sources") {
"//extensions/browser/zipfile_installer.h",
"//components/services/unzip/unzipper_impl.cc",
"//components/services/unzip/unzipper_impl.h",
+ "//ui/webui/mojo_web_ui_controller.cc",
+ "//ui/webui/mojo_web_ui_controller.h",
]
} else {
sources += [
@@ -656,6 +660,7 @@ repack("qtwebengine_repack_resources") {
]
if (enable_extensions) {
sources += [
+ "$root_gen_dir/qtwebengine/browser/extensions/resources/extensions_ui_qt_resources.pak",
"$root_gen_dir/chrome/component_extension_resources.pak",
"$root_gen_dir/extensions/extensions_renderer_resources.pak",
"$root_gen_dir/extensions/extensions_resources.pak",
@@ -664,6 +669,7 @@ repack("qtwebengine_repack_resources") {
"//chrome/browser/resources:component_extension_resources_grit",
"//extensions:extensions_renderer_resources_grit",
"//extensions:extensions_resources_grd_grit",
+ "//qtwebengine/browser/extensions/resources:resources_grit"
]
}
if (enable_webrtc) {
diff --git a/src/core/content_browser_client_qt.cpp b/src/core/content_browser_client_qt.cpp
index 015532ff9..1bda59a75 100644
--- a/src/core/content_browser_client_qt.cpp
+++ b/src/core/content_browser_client_qt.cpp
@@ -112,6 +112,7 @@
#endif
#if BUILDFLAG(ENABLE_EXTENSIONS)
+#include "content/public/browser/web_ui_controller_interface_binder.h"
#include "common/extensions/extensions_client_qt.h"
#include "components/guest_view/browser/guest_view_base.h"
#include "extensions/browser/api/mime_handler_private/mime_handler_private.h"
@@ -130,6 +131,8 @@
#include "extensions/extension_web_contents_observer_qt.h"
#include "extensions/extensions_browser_client_qt.h"
#include "net/plugin_response_interceptor_url_loader_throttle.h"
+#include "extensions/webui/extensions_ui_page_handler_qt.h"
+#include "extensions/webui/extensions_ui_qt.h"
#endif
#if QT_CONFIG(webengine_webchannel)
@@ -450,6 +453,9 @@ void ContentBrowserClientQt::RegisterBrowserInterfaceBindersForFrame(
#endif
#if BUILDFLAG(ENABLE_EXTENSIONS)
+ RegisterWebUIControllerInterfaceBinder<qtwebengine::mojom::ExtensionsUIHandlerFactory,
+ ExtensionsUIQt>(map);
+
map->Add<extensions::mime_handler::MimeHandlerService>(base::BindRepeating(&BindMimeHandlerService));
map->Add<extensions::mime_handler::BeforeUnloadControl>(base::BindRepeating(&BindBeforeUnloadControl));
const GURL &site = render_frame_host->GetSiteInstance()->GetSiteURL();
diff --git a/src/core/extensions/webui/extensions_ui_page_handler_qt.cpp b/src/core/extensions/webui/extensions_ui_page_handler_qt.cpp
new file mode 100644
index 000000000..2e88c393c
--- /dev/null
+++ b/src/core/extensions/webui/extensions_ui_page_handler_qt.cpp
@@ -0,0 +1,70 @@
+// Copyright (C) 2025 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "extensions_ui_page_handler_qt.h"
+
+#include "extensions/extension_system_qt.h"
+#include "extensions/webui/select_file_dialog.h"
+
+#include "extensions/browser/extension_registry.h"
+#include "extensions/extension_manager.h"
+#include "api/qwebengineextensionmanager.h"
+#include "profile_adapter.h"
+#include "profile_qt.h"
+#include "type_conversion.h"
+
+ExtensionsUIPageHandlerQt::ExtensionsUIPageHandlerQt(
+ content::WebUI *webui, Profile *profile,
+ mojo::PendingReceiver<qtwebengine::mojom::PageHandler> receiver,
+ mojo::PendingRemote<qtwebengine::mojom::Page> page)
+ : receiver_(this, std::move(receiver)), page_(std::move(page)), webui_(webui), profile_(profile)
+{
+}
+
+ExtensionsUIPageHandlerQt::~ExtensionsUIPageHandlerQt() { }
+
+void ExtensionsUIPageHandlerQt::GetAllExtensionInfo(GetAllExtensionInfoCallback callback)
+{
+ std::vector<qtwebengine::mojom::ExtensionInfoPtr> extensionsInfo;
+
+ auto add_to_list = [&extensionsInfo](const extensions::ExtensionSet &extensions,
+ bool is_enabled) {
+ for (auto extension : extensions) {
+ auto info = qtwebengine::mojom::ExtensionInfo::New();
+ info->name = extension->name();
+ info->description = extension->description();
+ info->version = extension->VersionString();
+ info->id = extension->id();
+ info->isEnabled = is_enabled;
+ extensionsInfo.push_back(std::move(info));
+ }
+ };
+
+ extensions::ExtensionRegistry *registry = extensions::ExtensionRegistry::Get(profile_);
+ add_to_list(registry->enabled_extensions(), true);
+ add_to_list(registry->disabled_extensions(), false);
+
+ std::move(callback).Run(std::move(extensionsInfo));
+}
+
+void ExtensionsUIPageHandlerQt::LoadExtension()
+{
+ SelectFileDialog::Show(
+ base::BindOnce(&ExtensionsUIPageHandlerQt::InnerLoadExtension, base::Unretained(this)),
+ base::FilePath(), webui_->GetWebContents());
+}
+
+void ExtensionsUIPageHandlerQt::InnerLoadExtension(const base::FilePath &path)
+{
+ auto profileAdapter = static_cast<QtWebEngineCore::ProfileQt *>(profile_)->profileAdapter();
+ QWebEngineExtensionManager *manager = profileAdapter->extensionManager();
+
+ QMetaObject::Connection *const connection = new QMetaObject::Connection;
+ *connection = QObject::connect(manager, &QWebEngineExtensionManager::extensionLoadFinished,
+ [this, connection]() {
+ page_->ReloadPage();
+ QObject::disconnect(*connection);
+ delete connection;
+ });
+ manager->loadExtension(QtWebEngineCore::toQt(path));
+}
diff --git a/src/core/extensions/webui/extensions_ui_page_handler_qt.h b/src/core/extensions/webui/extensions_ui_page_handler_qt.h
new file mode 100644
index 000000000..236c7df1b
--- /dev/null
+++ b/src/core/extensions/webui/extensions_ui_page_handler_qt.h
@@ -0,0 +1,39 @@
+// Copyright (C) 2025 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef EXTENSIONSUIPAGEHANDLERQT_H
+#define EXTENSIONSUIPAGEHANDLERQT_H
+
+#include "chrome/browser/profiles/profile.h"
+#include "content/public/browser/web_ui.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
+#include "qtwebengine/browser/extensions/webui/extensions_ui_qt.mojom.h"
+
+class ExtensionsUIPageHandlerQt : public qtwebengine::mojom::PageHandler
+{
+public:
+ ExtensionsUIPageHandlerQt(content::WebUI *webui, Profile *profile,
+ mojo::PendingReceiver<qtwebengine::mojom::PageHandler> receiver,
+ mojo::PendingRemote<qtwebengine::mojom::Page> page);
+
+ ExtensionsUIPageHandlerQt(const ExtensionsUIPageHandlerQt &) = delete;
+ ExtensionsUIPageHandlerQt &operator=(const ExtensionsUIPageHandlerQt &) = delete;
+
+ ~ExtensionsUIPageHandlerQt() override;
+
+ void GetAllExtensionInfo(GetAllExtensionInfoCallback callback) override;
+ void LoadExtension() override;
+
+private:
+ void InnerLoadExtension(const base::FilePath &path);
+
+ mojo::Receiver<qtwebengine::mojom::PageHandler> receiver_;
+ mojo::Remote<qtwebengine::mojom::Page> page_;
+ content::WebUI *webui_;
+ Profile *profile_;
+};
+
+#endif // EXTENSIONSUIPAGEHANDLERQT_H
diff --git a/src/core/extensions/webui/extensions_ui_qt.cpp b/src/core/extensions/webui/extensions_ui_qt.cpp
new file mode 100644
index 000000000..d72be5164
--- /dev/null
+++ b/src/core/extensions/webui/extensions_ui_qt.cpp
@@ -0,0 +1,48 @@
+// Copyright (C) 2025 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "extensions_ui_qt.h"
+
+#include "chrome/common/url_constants.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_ui_data_source.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/webui/webui_util.h"
+#include "qtwebengine/browser/extensions/resources/grit/extensions_ui_qt_resources.h"
+#include "qtwebengine/browser/extensions/resources/grit/extensions_ui_qt_resources_map.h"
+
+#include "extensions_ui_page_handler_qt.h"
+
+ExtensionsUIQt::ExtensionsUIQt(content::WebUI *web_ui) : ui::MojoWebUIController(web_ui, true)
+{
+ content::WebUIDataSource *source = content::WebUIDataSource::CreateAndAdd(
+ web_ui->GetWebContents()->GetBrowserContext(), chrome::kChromeUIExtensionsHost);
+
+ webui::SetupWebUIDataSource(
+ source, base::make_span(kExtensionsUiQtResources, kExtensionsUiQtResourcesSize),
+ IDR_EXTENSIONS_UI_QT_EXTENSIONS_UI_QT_HTML);
+
+ source->OverrideContentSecurityPolicy(network::mojom::CSPDirectiveName::TrustedTypes,
+ "trusted-types static-types polymer-html-literal "
+ "polymer-template-event-attribute-policy "
+ "lit-html-desktop;");
+}
+
+void ExtensionsUIQt::BindInterface(
+ mojo::PendingReceiver<qtwebengine::mojom::ExtensionsUIHandlerFactory> receiver)
+{
+ page_factory_receiver_.reset();
+ page_factory_receiver_.Bind(std::move(receiver));
+}
+
+void ExtensionsUIQt::CreatePageHandler(
+ mojo::PendingRemote<qtwebengine::mojom::Page> page,
+ mojo::PendingReceiver<qtwebengine::mojom::PageHandler> receiver)
+{
+ DCHECK(page);
+ Profile *profile = Profile::FromWebUI(web_ui());
+ page_handler_ = std::make_unique<ExtensionsUIPageHandlerQt>(
+ web_ui(), profile, std::move(receiver), std::move(page));
+}
+
+WEB_UI_CONTROLLER_TYPE_IMPL(ExtensionsUIQt)
diff --git a/src/core/extensions/webui/extensions_ui_qt.h b/src/core/extensions/webui/extensions_ui_qt.h
new file mode 100644
index 000000000..55f4c7505
--- /dev/null
+++ b/src/core/extensions/webui/extensions_ui_qt.h
@@ -0,0 +1,33 @@
+// Copyright (C) 2025 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef EXTENSIONS_UI_QT_H
+#define EXTENSIONS_UI_QT_H
+
+#include "qtwebengine/browser/extensions/webui/extensions_ui_qt.mojom.h"
+#include "ui/webui/mojo_web_ui_controller.h"
+
+class ExtensionsUIPageHandlerQt;
+
+class ExtensionsUIQt : public ui::MojoWebUIController,
+ public qtwebengine::mojom::ExtensionsUIHandlerFactory
+{
+public:
+ explicit ExtensionsUIQt(content::WebUI *web_ui);
+
+ ExtensionsUIQt(const ExtensionsUIQt &) = delete;
+ ExtensionsUIQt &operator=(const ExtensionsUIQt &) = delete;
+
+ void BindInterface(mojo::PendingReceiver<qtwebengine::mojom::ExtensionsUIHandlerFactory> receiver);
+
+private:
+ // qtwebengine::mojom::ExtensionsUIHandlerFactory
+ void CreatePageHandler(mojo::PendingRemote<qtwebengine::mojom::Page> page,
+ mojo::PendingReceiver<qtwebengine::mojom::PageHandler> receiver) override;
+
+ std::unique_ptr<ExtensionsUIPageHandlerQt> page_handler_;
+ mojo::Receiver<qtwebengine::mojom::ExtensionsUIHandlerFactory> page_factory_receiver_ { this };
+ WEB_UI_CONTROLLER_TYPE_DECL();
+};
+
+#endif // EXTENSIONS_UI_QT_H
diff --git a/src/core/extensions/webui/select_file_dialog.cpp b/src/core/extensions/webui/select_file_dialog.cpp
new file mode 100644
index 000000000..04eabff82
--- /dev/null
+++ b/src/core/extensions/webui/select_file_dialog.cpp
@@ -0,0 +1,51 @@
+// Copyright (C) 2025 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "select_file_dialog.h"
+
+#include "ui/shell_dialogs/selected_file_info.h"
+#include "ui/shell_dialogs/select_file_policy.h"
+#include "content/public/browser/web_contents.h"
+
+#include "content/public/browser/content_browser_client.h"
+#include "content/public/common/content_client.h"
+
+namespace content {
+extern ContentClient *GetContentClient();
+}
+
+SelectFileDialog::~SelectFileDialog()
+{
+ select_file_dialog_->ListenerDestroyed();
+}
+
+void SelectFileDialog::Show(SelectedCallback selected_callback, const base::FilePath &default_path,
+ content::WebContents *web_contents)
+{
+ // Dialog is self-deleting.
+ auto *dialog = new SelectFileDialog();
+ dialog->ShowDialog(std::move(selected_callback), default_path, web_contents);
+}
+
+void SelectFileDialog::FileSelected(const ui::SelectedFileInfo &file, int index)
+{
+ std::move(selected_callback_).Run(file.path());
+ delete this;
+}
+
+void SelectFileDialog::ShowDialog(SelectedCallback selected_callback,
+ const base::FilePath &default_path,
+ content::WebContents *web_contents)
+{
+ selected_callback_ = std::move(selected_callback);
+
+ select_file_dialog_ = ui::SelectFileDialog::Create(
+ this,
+ std::unique_ptr<ui::SelectFilePolicy>(
+ content::GetContentClient()->browser()->CreateSelectFilePolicy(web_contents)));
+
+ base::FilePath::StringType ext;
+ ui::SelectFileDialog::FileTypeInfo file_type_info;
+ select_file_dialog_->SelectFile(ui::SelectFileDialog::SELECT_FOLDER, std::u16string(),
+ default_path, &file_type_info, 0, ext, nullptr, nullptr);
+}
diff --git a/src/core/extensions/webui/select_file_dialog.h b/src/core/extensions/webui/select_file_dialog.h
new file mode 100644
index 000000000..0e2ee353d
--- /dev/null
+++ b/src/core/extensions/webui/select_file_dialog.h
@@ -0,0 +1,38 @@
+// Copyright (C) 2025 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef SELECT_FILE_DIALOG_H
+#define SELECT_FILE_DIALOG_H
+
+#include "ui/shell_dialogs/select_file_dialog.h"
+#include "base/functional/callback.h"
+
+typedef base::OnceCallback<void(const base::FilePath &)> SelectedCallback;
+
+namespace content {
+class WebContents;
+}
+class SelectFileDialog : public ui::SelectFileDialog::Listener
+{
+public:
+ SelectFileDialog(const SelectFileDialog &) = delete;
+ SelectFileDialog &operator=(const SelectFileDialog &) = delete;
+
+ static void Show(SelectedCallback selected_callback, const base::FilePath &default_path,
+ content::WebContents *web_contents);
+
+ // ui::SelectFileDialog::Listener
+ void FileSelected(const ui::SelectedFileInfo &file, int index) override;
+ void FileSelectionCanceled() override { }
+
+private:
+ SelectFileDialog() = default;
+ ~SelectFileDialog() override;
+
+ void ShowDialog(SelectedCallback selected_callback, const base::FilePath &default_path,
+ content::WebContents *web_contents);
+
+ scoped_refptr<ui::SelectFileDialog> select_file_dialog_;
+ SelectedCallback selected_callback_;
+};
+#endif // SELECT_FILE_DIALOG_H
diff --git a/src/core/net/webui_controller_factory_qt.cpp b/src/core/net/webui_controller_factory_qt.cpp
index e35c88408..ac6475f95 100644
--- a/src/core/net/webui_controller_factory_qt.cpp
+++ b/src/core/net/webui_controller_factory_qt.cpp
@@ -48,17 +48,9 @@
// #include "chrome/browser/ui/webui/certificate_viewer_ui.h"
// #endif
-// #if BUILDFLAG(ENABLE_EXTENSIONS)
-// #include "chrome/browser/extensions/extension_web_ui.h"
-// #include "chrome/browser/ui/webui/extensions/extensions_ui.h"
-// #include "chrome/common/extensions/extension_constants.h"
-// #include "extensions/browser/extension_registry.h"
-// #include "extensions/browser/extension_system.h"
-// #include "extensions/common/constants.h"
-// #include "extensions/common/extension.h"
-// #include "extensions/common/feature_switch.h"
-// #include "extensions/common/manifest.h"
-// #endif
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+#include "extensions/webui/extensions_ui_qt.h"
+#endif
using content::WebUI;
using content::WebUIController;
@@ -117,10 +109,10 @@ WebUIFactoryFunction GetWebUIFactoryFunction(WebUI *web_ui, Profile *profile, co
// if (url.host_piece() == chrome::kChromeUICertificateViewerHost)
// return &NewWebUI<CertificateViewerUI>;
//#endif // USE_NSS_CERTS && USE_AURA
-//#if BUILDFLAG(ENABLE_EXTENSIONS)
-// if (url.host_piece() == chrome::kChromeUIExtensionsFrameHost)
-// return &NewWebUI<extensions::ExtensionsUI>;
-//#endif
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+ if (url.host_piece() == chrome::kChromeUIExtensionsHost)
+ return &NewWebUI<ExtensionsUIQt>;
+#endif
//#if BUILDFLAG(ENABLE_PRINT_PREVIEW)
// if (url.host_piece() == chrome::kChromeUIPrintHost &&
// !profile->GetPrefs()->GetBoolean(prefs::kPrintPreviewDisabled)) {
diff --git a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp
index ee754c77a..7dc71dd92 100644
--- a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp
+++ b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp
@@ -3353,7 +3353,7 @@ void tst_QWebEngineView::webUIURLs_data()
QTest::newRow("discards") << QUrl("chrome://discards") << false;
QTest::newRow("download-internals") << QUrl("chrome://download-internals") << false;
QTest::newRow("downloads") << QUrl("chrome://downloads") << false;
- QTest::newRow("extensions") << QUrl("chrome://extensions") << false;
+ QTest::newRow("extensions") << QUrl("chrome://extensions") << true;
QTest::newRow("extensions-internals") << QUrl("chrome://extensions-internals") << false;
QTest::newRow("flags") << QUrl("chrome://flags") << false;
QTest::newRow("gcm-internals") << QUrl("chrome://gcm-internals") << false;