Use Chrome file dialogs on all platforms and runtimes (fixes issue #3314)

All file dialogs irrespective of source, platform and runtime will now be
routed through CefFileDialogManager and trigger CefDialogHandler callbacks
(see issue #3293).

Adds Chrome runtime support for CefBrowserHost::RunFileDialog and
CefDialogHandler callbacks.

Adds Alloy runtime support for internal GTK file and print dialogs on Linux
subject to the following limitations:

1. Internal GTK implementation:
   - Cannot be used with multi-threaded-message-loop because Chromium's
     internal GTK implementation is not thread-safe (does not use GDK threads).
   - Dialogs will not be modal to application windows when used with off-screen
     rendering due to lack of access to the client's top-level GtkWindow.
2. Cefclient CefDialogHandler implementation:
   - Cannot be used with Views because it requires a top-level GtkWindow.

Due to the above limitations no dialog implementation is currently provided for
Views + multi-threaded-message-loop on Linux. In cases where both
implementations are supported the cefclient version is now behind an optional
`--use-client-dialogs` command-line flag.

Expressly forbids multiple simultaneous file dialogs with the internal platform
implementation which uses modal dialogs. CefDialogHandler will still be notified
and can optionally handle each request without a modal dialog (see issue #3154).

Removes some RunFileDialog parameters that are not supported by the Chrome file
dialog implementation (selected_accept_filter parameter, cef_file_dialog_mode_t
overwrite/read-only flags).
This commit is contained in:
Marshall Greenblatt 2022-04-15 15:55:23 -04:00
parent edef01f579
commit 2ea7459a89
75 changed files with 1566 additions and 2231 deletions

View File

@ -414,8 +414,6 @@ static_library("libcef_static") {
"libcef/browser/alloy/alloy_browser_main.h",
"libcef/browser/alloy/alloy_content_browser_client.cc",
"libcef/browser/alloy/alloy_content_browser_client.h",
"libcef/browser/alloy/alloy_dialog_util.cc",
"libcef/browser/alloy/alloy_dialog_util.h",
"libcef/browser/alloy/alloy_download_util.cc",
"libcef/browser/alloy/alloy_download_util.h",
"libcef/browser/alloy/browser_platform_delegate_alloy.cc",
@ -550,9 +548,10 @@ static_library("libcef_static") {
"libcef/browser/extensions/value_store/cef_value_store.h",
"libcef/browser/extensions/value_store/cef_value_store_factory.cc",
"libcef/browser/extensions/value_store/cef_value_store_factory.h",
"libcef/browser/file_dialog_runner.h",
"libcef/browser/file_dialog_manager.cc",
"libcef/browser/file_dialog_manager.h",
"libcef/browser/file_dialog_runner.cc",
"libcef/browser/file_dialog_runner.h",
"libcef/browser/frame_host_impl.cc",
"libcef/browser/frame_host_impl.h",
"libcef/browser/frame_service_base.h",
@ -1019,8 +1018,6 @@ static_library("libcef_static") {
"libcef/browser/native/browser_platform_delegate_native_win.cc",
"libcef/browser/native/browser_platform_delegate_native_win.h",
"libcef/browser/native/cursor_util_win.cc",
"libcef/browser/native/file_dialog_runner_win.cc",
"libcef/browser/native/file_dialog_runner_win.h",
"libcef/browser/native/javascript_dialog_runner_win.cc",
"libcef/browser/native/javascript_dialog_runner_win.h",
"libcef/browser/native/menu_2.cc",
@ -1092,8 +1089,6 @@ static_library("libcef_static") {
sources += includes_mac + [
"libcef/browser/native/browser_platform_delegate_native_mac.h",
"libcef/browser/native/browser_platform_delegate_native_mac.mm",
"libcef/browser/native/file_dialog_runner_mac.h",
"libcef/browser/native/file_dialog_runner_mac.mm",
"libcef/browser/native/javascript_dialog_runner_mac.h",
"libcef/browser/native/javascript_dialog_runner_mac.mm",
"libcef/browser/native/menu_runner_mac.h",

View File

@ -33,7 +33,7 @@
// by hand. See the translator.README.txt file in the tools directory for
// more information.
//
// $hash=b80e84c0039ab45d5c4562d64b67a84766c0dab3$
// $hash=b1c1e44e6d3842064ef6e5b9823173f7ec1fcccc$
//
#ifndef CEF_INCLUDE_CAPI_CEF_BROWSER_CAPI_H_
@ -205,15 +205,12 @@ typedef struct _cef_run_file_dialog_callback_t {
cef_base_ref_counted_t base;
///
// Called asynchronously after the file dialog is dismissed.
// |selected_accept_filter| is the 0-based index of the value selected from
// the accept filters array passed to cef_browser_host_t::RunFileDialog.
// |file_paths| will be a single value or a list of values depending on the
// dialog mode. If the selection was cancelled |file_paths| will be NULL.
// Called asynchronously after the file dialog is dismissed. |file_paths| will
// be a single value or a list of values depending on the dialog mode. If the
// selection was cancelled |file_paths| will be NULL.
///
void(CEF_CALLBACK* on_file_dialog_dismissed)(
struct _cef_run_file_dialog_callback_t* self,
int selected_accept_filter,
cef_string_list_t file_paths);
} cef_run_file_dialog_callback_t;
@ -391,11 +388,10 @@ typedef struct _cef_browser_host_t {
// selectable file types and may any combination of (a) valid lower-cased MIME
// types (e.g. "text/*" or "image/*"), (b) individual file extensions (e.g.
// ".txt" or ".png"), or (c) combined description and file extension delimited
// using "|" and ";" (e.g. "Image Types|.png;.gif;.jpg").
// |selected_accept_filter| is the 0-based index of the filter that will be
// selected by default. |callback| will be executed after the dialog is
// dismissed or immediately if another dialog is already pending. The dialog
// will be initiated asynchronously on the UI thread.
// using "|" and ";" (e.g. "Image Types|.png;.gif;.jpg"). |callback| will be
// executed after the dialog is dismissed or immediately if another dialog is
// already pending. The dialog will be initiated asynchronously on the UI
// thread.
///
void(CEF_CALLBACK* run_file_dialog)(
struct _cef_browser_host_t* self,
@ -403,7 +399,6 @@ typedef struct _cef_browser_host_t {
const cef_string_t* title,
const cef_string_t* default_file_path,
cef_string_list_t accept_filters,
int selected_accept_filter,
struct _cef_run_file_dialog_callback_t* callback);
///

View File

@ -33,7 +33,7 @@
// by hand. See the translator.README.txt file in the tools directory for
// more information.
//
// $hash=0f56154217707d141912dc8a298279df8df04311$
// $hash=dc579beb1f25f9bbdb72afb4b5b381e129f84e31$
//
#ifndef CEF_INCLUDE_CAPI_CEF_DIALOG_HANDLER_CAPI_H_
@ -57,14 +57,11 @@ typedef struct _cef_file_dialog_callback_t {
cef_base_ref_counted_t base;
///
// Continue the file selection. |selected_accept_filter| should be the 0-based
// index of the value selected from the accept filters array passed to
// cef_dialog_handler_t::OnFileDialog. |file_paths| should be a single value
// or a list of values depending on the dialog mode. An NULL |file_paths|
// value is treated the same as calling cancel().
// Continue the file selection. |file_paths| should be a single value or a
// list of values depending on the dialog mode. An NULL |file_paths| value is
// treated the same as calling cancel().
///
void(CEF_CALLBACK* cont)(struct _cef_file_dialog_callback_t* self,
int selected_accept_filter,
cef_string_list_t file_paths);
///
@ -93,10 +90,9 @@ typedef struct _cef_dialog_handler_t {
// (a) valid lower-cased MIME types (e.g. "text/*" or "image/*"), (b)
// individual file extensions (e.g. ".txt" or ".png"), or (c) combined
// description and file extension delimited using "|" and ";" (e.g. "Image
// Types|.png;.gif;.jpg"). |selected_accept_filter| is the 0-based index of
// the filter that should be selected by default. To display a custom dialog
// return true (1) and execute |callback| either inline or at a later time. To
// display the default dialog return false (0).
// Types|.png;.gif;.jpg"). To display a custom dialog return true (1) and
// execute |callback| either inline or at a later time. To display the default
// dialog return false (0).
///
int(CEF_CALLBACK* on_file_dialog)(
struct _cef_dialog_handler_t* self,
@ -105,7 +101,6 @@ typedef struct _cef_dialog_handler_t {
const cef_string_t* title,
const cef_string_t* default_file_path,
cef_string_list_t accept_filters,
int selected_accept_filter,
struct _cef_file_dialog_callback_t* callback);
} cef_dialog_handler_t;

View File

@ -42,13 +42,13 @@
// way that may cause binary incompatibility with other builds. The universal
// hash value will change if any platform is affected whereas the platform hash
// values will change only if that particular platform is affected.
#define CEF_API_HASH_UNIVERSAL "1d7470ed03e8ddca6998284bef50694f5bad036c"
#define CEF_API_HASH_UNIVERSAL "02da3a1d216f7e3d3dcb54658d939e3d4ebf1aa0"
#if defined(OS_WIN)
#define CEF_API_HASH_PLATFORM "1c2e8c364d8dead07b5601bcac5c51392eb0821d"
#define CEF_API_HASH_PLATFORM "ab8b744ba6e0275c87e5640af47571692957a7b4"
#elif defined(OS_MAC)
#define CEF_API_HASH_PLATFORM "934c730bb8b18a6b987612e5e99b28173f189c72"
#define CEF_API_HASH_PLATFORM "77ae587ff6423e3f26dcc950ef5a894e341ddf1c"
#elif defined(OS_LINUX)
#define CEF_API_HASH_PLATFORM "f45d62cfe6b26112a91404c0ff1332e3ff153b8b"
#define CEF_API_HASH_PLATFORM "1d805fef4907c18098039d89896ab8fec3d5e70a"
#endif
#ifdef __cplusplus

View File

@ -206,14 +206,11 @@ class CefRunFileDialogCallback : public virtual CefBaseRefCounted {
public:
///
// Called asynchronously after the file dialog is dismissed.
// |selected_accept_filter| is the 0-based index of the value selected from
// the accept filters array passed to CefBrowserHost::RunFileDialog.
// |file_paths| will be a single value or a list of values depending on the
// dialog mode. If the selection was cancelled |file_paths| will be empty.
///
/*--cef(index_param=selected_accept_filter,optional_param=file_paths)--*/
/*--cef(optional_param=file_paths)--*/
virtual void OnFileDialogDismissed(
int selected_accept_filter,
const std::vector<CefString>& file_paths) = 0;
};
@ -421,19 +418,17 @@ class CefBrowserHost : public virtual CefBaseRefCounted {
// selectable file types and may any combination of (a) valid lower-cased MIME
// types (e.g. "text/*" or "image/*"), (b) individual file extensions (e.g.
// ".txt" or ".png"), or (c) combined description and file extension delimited
// using "|" and ";" (e.g. "Image Types|.png;.gif;.jpg").
// |selected_accept_filter| is the 0-based index of the filter that will be
// selected by default. |callback| will be executed after the dialog is
// dismissed or immediately if another dialog is already pending. The dialog
// will be initiated asynchronously on the UI thread.
// using "|" and ";" (e.g. "Image Types|.png;.gif;.jpg"). |callback| will be
// executed after the dialog is dismissed or immediately if another dialog is
// already pending. The dialog will be initiated asynchronously on the UI
// thread.
///
/*--cef(optional_param=title,optional_param=default_file_path,
optional_param=accept_filters,index_param=selected_accept_filter)--*/
optional_param=accept_filters)--*/
virtual void RunFileDialog(FileDialogMode mode,
const CefString& title,
const CefString& default_file_path,
const std::vector<CefString>& accept_filters,
int selected_accept_filter,
CefRefPtr<CefRunFileDialogCallback> callback) = 0;
///

View File

@ -48,16 +48,12 @@
class CefFileDialogCallback : public virtual CefBaseRefCounted {
public:
///
// Continue the file selection. |selected_accept_filter| should be the 0-based
// index of the value selected from the accept filters array passed to
// CefDialogHandler::OnFileDialog. |file_paths| should be a single value or a
// Continue the file selection. |file_paths| should be a single value or a
// list of values depending on the dialog mode. An empty |file_paths| value is
// treated the same as calling Cancel().
///
/*--cef(capi_name=cont,index_param=selected_accept_filter,
optional_param=file_paths)--*/
virtual void Continue(int selected_accept_filter,
const std::vector<CefString>& file_paths) = 0;
/*--cef(capi_name=cont,optional_param=file_paths)--*/
virtual void Continue(const std::vector<CefString>& file_paths) = 0;
///
// Cancel the file selection.
@ -85,19 +81,17 @@ class CefDialogHandler : public virtual CefBaseRefCounted {
// (a) valid lower-cased MIME types (e.g. "text/*" or "image/*"),
// (b) individual file extensions (e.g. ".txt" or ".png"), or (c) combined
// description and file extension delimited using "|" and ";" (e.g.
// "Image Types|.png;.gif;.jpg"). |selected_accept_filter| is the 0-based
// index of the filter that should be selected by default. To display a custom
// dialog return true and execute |callback| either inline or at a later time.
// To display the default dialog return false.
// "Image Types|.png;.gif;.jpg"). To display a custom dialog return true and
// execute |callback| either inline or at a later time. To display the default
// dialog return false.
///
/*--cef(optional_param=title,optional_param=default_file_path,
optional_param=accept_filters,index_param=selected_accept_filter)--*/
optional_param=accept_filters)--*/
virtual bool OnFileDialog(CefRefPtr<CefBrowser> browser,
FileDialogMode mode,
const CefString& title,
const CefString& default_file_path,
const std::vector<CefString>& accept_filters,
int selected_accept_filter,
CefRefPtr<CefFileDialogCallback> callback) {
return false;
}

View File

@ -2237,26 +2237,6 @@ typedef enum {
// already exists.
///
FILE_DIALOG_SAVE,
///
// General mask defining the bits used for the type values.
///
FILE_DIALOG_TYPE_MASK = 0xFF,
// Qualifiers.
// Any of the type values above can be augmented by one or more qualifiers.
// These qualifiers further define the dialog behavior.
///
// Prompt to overwrite if the user selects an existing file with the Save
// dialog.
///
FILE_DIALOG_OVERWRITEPROMPT_FLAG = 0x01000000,
///
// Do not display read-only files.
///
FILE_DIALOG_HIDEREADONLY_FLAG = 0x02000000,
} cef_file_dialog_mode_t;
///

View File

@ -32,6 +32,7 @@
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/command_line.h"
#include "chrome/browser/file_select_helper.h"
#include "chrome/browser/picture_in_picture/picture_in_picture_window_manager.h"
#include "content/browser/gpu/compositor_util.h"
#include "content/public/browser/desktop_media_id.h"
@ -348,27 +349,6 @@ void AlloyBrowserHostImpl::SetZoomLevel(double zoomLevel) {
}
}
void AlloyBrowserHostImpl::RunFileDialog(
FileDialogMode mode,
const CefString& title,
const CefString& default_file_path,
const std::vector<CefString>& accept_filters,
int selected_accept_filter,
CefRefPtr<CefRunFileDialogCallback> callback) {
if (!CEF_CURRENTLY_ON_UIT()) {
CEF_POST_TASK(CEF_UIT,
base::BindOnce(&AlloyBrowserHostImpl::RunFileDialog, this,
mode, title, default_file_path, accept_filters,
selected_accept_filter, callback));
return;
}
EnsureFileDialogManager();
file_dialog_manager_->RunFileDialog(mode, title, default_file_path,
accept_filters, selected_accept_filter,
callback);
}
void AlloyBrowserHostImpl::Print() {
if (!CEF_CURRENTLY_ON_UIT()) {
CEF_POST_TASK(CEF_UIT, base::BindOnce(&AlloyBrowserHostImpl::Print, this));
@ -666,8 +646,6 @@ void AlloyBrowserHostImpl::DestroyBrowser() {
OnBeforeClose();
// Destroy any platform constructs first.
if (file_dialog_manager_.get())
file_dialog_manager_->Destroy();
if (javascript_dialog_manager_.get())
javascript_dialog_manager_->Destroy();
if (menu_manager_.get())
@ -750,13 +728,6 @@ void AlloyBrowserHostImpl::OnSetFocus(cef_focus_source_t source) {
platform_delegate_->SetFocus(true);
}
void AlloyBrowserHostImpl::RunFileChooser(
const CefFileDialogRunner::FileChooserParams& params,
CefFileDialogRunner::RunFileChooserCallback callback) {
EnsureFileDialogManager();
file_dialog_manager_->RunFileChooser(params, std::move(callback));
}
void AlloyBrowserHostImpl::EnterFullscreenModeForTab(
content::RenderFrameHost* requesting_frame,
const blink::mojom::FullscreenOptions& options) {
@ -1278,8 +1249,9 @@ void AlloyBrowserHostImpl::RunFileChooser(
content::RenderFrameHost* render_frame_host,
scoped_refptr<content::FileSelectListener> listener,
const blink::mojom::FileChooserParams& params) {
EnsureFileDialogManager();
file_dialog_manager_->RunFileChooser(listener, params);
// This will eventually call into CefFileDialogManager.
FileSelectHelper::RunFileChooser(render_frame_host, std::move(listener),
params);
}
bool AlloyBrowserHostImpl::HandleContextMenu(
@ -1575,11 +1547,3 @@ void AlloyBrowserHostImpl::UpdateDragCursor(
if (platform_delegate_)
platform_delegate_->UpdateDragCursor(operation);
}
void AlloyBrowserHostImpl::EnsureFileDialogManager() {
CEF_REQUIRE_UIT();
if (!file_dialog_manager_.get() && platform_delegate_) {
file_dialog_manager_.reset(new CefFileDialogManager(
this, platform_delegate_->CreateFileDialogRunner()));
}
}

View File

@ -16,7 +16,6 @@
#include "include/cef_frame.h"
#include "libcef/browser/browser_host_base.h"
#include "libcef/browser/browser_info.h"
#include "libcef/browser/file_dialog_manager.h"
#include "libcef/browser/frame_host_impl.h"
#include "libcef/browser/javascript_dialog_manager.h"
#include "libcef/browser/menu_manager.h"
@ -83,12 +82,6 @@ class AlloyBrowserHostImpl : public CefBrowserHostBase,
CefWindowHandle GetOpenerWindowHandle() override;
double GetZoomLevel() override;
void SetZoomLevel(double zoomLevel) override;
void RunFileDialog(FileDialogMode mode,
const CefString& title,
const CefString& default_file_path,
const std::vector<CefString>& accept_filters,
int selected_accept_filter,
CefRefPtr<CefRunFileDialogCallback> callback) override;
void Print() override;
void PrintToPDF(const CefString& path,
const CefPdfPrintSettings& settings,
@ -178,12 +171,6 @@ class AlloyBrowserHostImpl : public CefBrowserHostBase,
void OnSetFocus(cef_focus_source_t source) override;
// Run the file chooser dialog specified by |params|. Only a single dialog may
// be pending at any given time. |callback| will be executed asynchronously
// after the dialog is dismissed or if another dialog is already pending.
void RunFileChooser(const CefFileDialogRunner::FileChooserParams& params,
CefFileDialogRunner::RunFileChooserCallback callback);
bool HandleContextMenu(content::WebContents* web_contents,
const content::ContextMenuParams& params);
@ -329,9 +316,6 @@ class AlloyBrowserHostImpl : public CefBrowserHostBase,
// Give the platform delegate an opportunity to create the host window.
bool CreateHostWindow();
// Create the CefFileDialogManager if it doesn't already exist.
void EnsureFileDialogManager();
void StartAudioCapturer();
void OnRecentlyAudibleTimerFired();
@ -349,9 +333,6 @@ class AlloyBrowserHostImpl : public CefBrowserHostBase,
// on the UI thread.
bool window_destroyed_ = false;
// Used for creating and managing file dialogs.
std::unique_ptr<CefFileDialogManager> file_dialog_manager_;
// Used for creating and managing JavaScript dialogs.
std::unique_ptr<CefJavaScriptDialogManager> javascript_dialog_manager_;

View File

@ -13,6 +13,7 @@
#include "libcef/browser/context.h"
#include "libcef/browser/devtools/devtools_manager_delegate.h"
#include "libcef/browser/extensions/extension_system_factory.h"
#include "libcef/browser/file_dialog_runner.h"
#include "libcef/browser/net/chrome_scheme_handler.h"
#include "libcef/browser/printing/constrained_window_views_client.h"
#include "libcef/browser/thread_util.h"
@ -75,11 +76,23 @@
#if BUILDFLAG(IS_LINUX)
#include "base/path_service.h"
#include "chrome/browser/themes/theme_service_aura_linux.h"
#include "chrome/browser/ui/views/theme_profile_key.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/grit/chromium_strings.h"
#include "components/os_crypt/key_storage_config_linux.h"
#include "libcef/browser/printing/print_dialog_linux.h"
#include "ui/base/cursor/cursor_factory.h"
#include "ui/base/ime/input_method.h"
#include "ui/base/ime/linux/fake_input_method_context_factory.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/linux/linux_ui_delegate.h"
#include "ui/ozone/public/ozone_platform.h"
#include "ui/views/linux_ui/linux_ui.h"
#if BUILDFLAG(USE_GTK)
#include "ui/gtk/gtk_ui_factory.h"
#endif
#endif // BUILDFLAG(IS_LINUX)
#if BUILDFLAG(ENABLE_MEDIA_FOUNDATION_WIDEVINE_CDM)
@ -90,6 +103,75 @@
#include "chrome/browser/component_updater/widevine_cdm_component_installer.h"
#endif
namespace {
#if BUILDFLAG(IS_LINUX)
std::unique_ptr<views::LinuxUI> BuildLinuxUI() {
// We can't use GtkUi in combination with multi-threaded-message-loop because
// Chromium's GTK implementation doesn't use GDK threads.
if (!!CefContext::Get()->settings().multi_threaded_message_loop)
return nullptr;
// If the ozone backend hasn't provided a LinuxUiDelegate, don't try to create
// a LinuxUi instance as this may result in a crash in toolkit initialization.
if (!ui::LinuxUiDelegate::GetInstance())
return nullptr;
// GtkUi is the only LinuxUI implementation for now.
#if BUILDFLAG(USE_GTK)
return BuildGtkUi();
#else
return nullptr;
#endif
}
// Based on chrome_browser_main_extra_parts_views_linux.cc
void ToolkitInitializedLinux() {
if (auto linux_ui = BuildLinuxUI()) {
linux_ui->SetUseSystemThemeCallback(
base::BindRepeating([](aura::Window* window) {
if (!window)
return true;
return ThemeServiceAuraLinux::ShouldUseSystemThemeForProfile(
GetThemeProfileForWindow(window));
}));
linux_ui->Initialize();
views::LinuxUI::SetInstance(std::move(linux_ui));
// Cursor theme changes are tracked by LinuxUI (via a CursorThemeManager
// implementation). Start observing them once it's initialized.
ui::CursorFactory::GetInstance()->ObserveThemeChanges();
} else {
// In case if GTK is not used, input method factory won't be set for X11 and
// Ozone/X11. Set a fake one instead to avoid crashing browser later.
DCHECK(!ui::LinuxInputMethodContextFactory::instance());
// Try to create input method through Ozone so that the backend has a chance
// to set factory by itself.
ui::OzonePlatform::GetInstance()->CreateInputMethod(
nullptr, gfx::kNullAcceleratedWidget);
}
// If factory is not set, set a fake instance.
if (!ui::LinuxInputMethodContextFactory::instance()) {
ui::LinuxInputMethodContextFactory::SetInstance(
new ui::FakeInputMethodContextFactory());
}
auto create_print_dialog_func =
printing::PrintingContextLinux::SetCreatePrintDialogFunction(
&CefPrintDialogLinux::CreatePrintDialog);
auto pdf_paper_size_func =
printing::PrintingContextLinux::SetPdfPaperSizeFunction(
&CefPrintDialogLinux::GetPdfPaperSize);
CefPrintDialogLinux::SetDefaultPrintingContextFuncs(create_print_dialog_func,
pdf_paper_size_func);
}
#endif // BUILDFLAG(IS_LINUX)
} // namespace
AlloyBrowserMainParts::AlloyBrowserMainParts(
content::MainFunctionParams parameters)
: BrowserMainParts(), parameters_(std::move(parameters)) {}
@ -98,16 +180,6 @@ AlloyBrowserMainParts::~AlloyBrowserMainParts() {
constrained_window::SetConstrainedWindowViewsClient(nullptr);
}
int AlloyBrowserMainParts::PreEarlyInitialization() {
#if defined(USE_AURA) && BUILDFLAG(IS_LINUX)
// TODO(linux): Consider using a real input method or
// views::LinuxUI::SetInstance.
ui::InitializeInputMethodForTesting();
#endif
return content::RESULT_CODE_NORMAL_EXIT;
}
void AlloyBrowserMainParts::ToolkitInitialized() {
SetConstrainedWindowViewsClient(CreateCefConstrainedWindowViewsClient());
#if defined(USE_AURA)
@ -122,6 +194,10 @@ void AlloyBrowserMainParts::ToolkitInitialized() {
#else
views_delegate_ = std::make_unique<views::DesktopTestViewsDelegate>();
#endif
#if BUILDFLAG(IS_LINUX)
ToolkitInitializedLinux();
#endif
}
void AlloyBrowserMainParts::PreCreateMainMessageLoop() {
@ -148,11 +224,6 @@ void AlloyBrowserMainParts::PreCreateMainMessageLoop() {
void AlloyBrowserMainParts::PostCreateMainMessageLoop() {
#if BUILDFLAG(IS_LINUX)
printing::PrintingContextLinux::SetCreatePrintDialogFunction(
&CefPrintDialogLinux::CreatePrintDialog);
printing::PrintingContextLinux::SetPdfPaperSizeFunction(
&CefPrintDialogLinux::GetPdfPaperSize);
const base::CommandLine* command_line =
base::CommandLine::ForCurrentProcess();
@ -241,6 +312,7 @@ int AlloyBrowserMainParts::PreMainMessageLoopRun() {
PluginFinder::GetInstance()->Init();
scheme::RegisterWebUIControllerFactory();
file_dialog_runner::RegisterFactory();
#if BUILDFLAG(ENABLE_MEDIA_FOUNDATION_WIDEVINE_CDM) || \
BUILDFLAG(ENABLE_WIDEVINE_CDM_COMPONENT)

View File

@ -42,7 +42,6 @@ class AlloyBrowserMainParts : public content::BrowserMainParts {
~AlloyBrowserMainParts() override;
int PreEarlyInitialization() override;
void ToolkitInitialized() override;
void PreCreateMainMessageLoop() override;
void PostCreateMainMessageLoop() override;

View File

@ -68,6 +68,7 @@
#include "chrome/browser/profiles/renderer_updater_factory.h"
#include "chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.h"
#include "chrome/browser/spellchecker/spell_check_host_chrome_impl.h"
#include "chrome/browser/ui/chrome_select_file_policy.h"
#include "chrome/common/chrome_content_client.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
@ -576,6 +577,12 @@ void AlloyContentBrowserClient::GetAdditionalViewSourceSchemes(
additional_schemes->push_back(extensions::kExtensionScheme);
}
std::unique_ptr<ui::SelectFilePolicy>
AlloyContentBrowserClient::CreateSelectFilePolicy(
content::WebContents* web_contents) {
return std::make_unique<ChromeSelectFilePolicy>(web_contents);
}
void AlloyContentBrowserClient::GetAdditionalAllowedSchemesForFileSystem(
std::vector<std::string>* additional_allowed_schemes) {
ContentBrowserClient::GetAdditionalAllowedSchemesForFileSystem(

View File

@ -58,6 +58,8 @@ class AlloyContentBrowserClient : public content::ContentBrowserClient {
std::vector<std::string>* additional_schemes) override;
void GetAdditionalViewSourceSchemes(
std::vector<std::string>* additional_schemes) override;
std::unique_ptr<ui::SelectFilePolicy> CreateSelectFilePolicy(
content::WebContents* web_contents) override;
void GetAdditionalAllowedSchemesForFileSystem(
std::vector<std::string>* additional_allowed_schemes) override;
bool IsWebUIAllowedToMakeNetworkRequests(const url::Origin& origin) override;

View File

@ -1,49 +0,0 @@
// Copyright 2021 The Chromium Embedded Framework 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 "libcef/browser/alloy/alloy_dialog_util.h"
#include "libcef/browser/alloy/alloy_browser_host_impl.h"
#include "libcef/browser/extensions/browser_extensions_util.h"
#include "libcef/browser/file_dialog_runner.h"
#include "base/strings/utf_string_conversions.h"
namespace alloy {
void RunFileChooser(content::WebContents* web_contents,
const blink::mojom::FileChooserParams& params,
RunFileChooserCallback callback) {
CefRefPtr<AlloyBrowserHostImpl> browser = static_cast<AlloyBrowserHostImpl*>(
extensions::GetOwnerBrowserForHost(web_contents->GetRenderViewHost(),
nullptr)
.get());
if (!browser) {
LOG(ERROR) << "Failed to identify browser; canceling file dialog";
std::move(callback).Run(-1, {});
return;
}
CefFileDialogRunner::FileChooserParams cef_params;
cef_params.mode = params.mode;
cef_params.default_file_name = params.default_file_name;
cef_params.accept_types = params.accept_types;
browser->RunFileChooser(cef_params, std::move(callback));
}
// Based on net/base/filename_util_internal.cc FilePathToString16().
std::u16string FilePathTypeToString16(const base::FilePath::StringType& str) {
std::u16string result;
#if BUILDFLAG(IS_WIN)
result.assign(str.begin(), str.end());
#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
if (!str.empty()) {
base::UTF8ToUTF16(str.c_str(), str.size(), &result);
}
#endif
return result;
}
} // namespace alloy

View File

@ -1,37 +0,0 @@
// Copyright 2021 The Chromium Embedded Framework Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be found
// in the LICENSE file.
#ifndef CEF_LIBCEF_BROWSER_ALLOY_ALLOY_DIALOG_UTIL_H_
#define CEF_LIBCEF_BROWSER_ALLOY_ALLOY_DIALOG_UTIL_H_
#pragma once
#include <string>
#include <vector>
#include "base/callback.h"
#include "base/files/file_path.h"
#include "third_party/blink/public/mojom/choosers/file_chooser.mojom.h"
namespace content {
class WebContents;
}
namespace alloy {
// The argument vector will be empty if the dialog was canceled.
using RunFileChooserCallback =
base::OnceCallback<void(int /*selected_accept_filter*/,
const std::vector<base::FilePath>& /*file_paths*/)>;
// Display the file chooser dialog. Execute |callback| on completion.
// Called from patched chrome/ files.
void RunFileChooser(content::WebContents* web_contents,
const blink::mojom::FileChooserParams& params,
RunFileChooserCallback callback);
std::u16string FilePathTypeToString16(const base::FilePath::StringType& str);
} // namespace alloy
#endif // CEF_LIBCEF_BROWSER_ALLOY_ALLOY_DIALOG_UTIL_H_

View File

@ -129,13 +129,12 @@ base::Time ChromeProfileAlloy::GetStartTime() const {
}
base::FilePath ChromeProfileAlloy::last_selected_directory() {
NOTREACHED();
return base::FilePath();
return last_selected_directory_;
}
void ChromeProfileAlloy::set_last_selected_directory(
const base::FilePath& path) {
NOTREACHED();
last_selected_directory_ = path;
}
GURL ChromeProfileAlloy::GetHomePage() {

View File

@ -8,6 +8,7 @@
#ifndef CEF_LIBCEF_BROWSER_ALLOY_CHROME_PROFILE_ALLOY_H_
#define CEF_LIBCEF_BROWSER_ALLOY_CHROME_PROFILE_ALLOY_H_
#include "base/files/file_path.h"
#include "chrome/browser/profiles/profile.h"
// This file provides a stub implementation of Chrome's Profile object for use
@ -54,6 +55,7 @@ class ChromeProfileAlloy : public Profile {
private:
std::unique_ptr<variations::VariationsClient> variations_client_;
base::FilePath last_selected_directory_;
};
#endif // CEF_LIBCEF_BROWSER_ALLOY_CHROME_PROFILE_ALLOY_H_

View File

@ -20,11 +20,14 @@
#include "chrome/browser/spellchecker/spellcheck_service.h"
#include "components/favicon/core/favicon_url.h"
#include "components/spellcheck/common/spellcheck_features.h"
#include "content/browser/renderer_host/render_frame_host_impl.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/download_manager.h"
#include "content/public/browser/download_request_utils.h"
#include "content/public/browser/file_select_listener.h"
#include "content/public/browser/navigation_entry.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/shell_dialogs/select_file_policy.h"
#if BUILDFLAG(IS_MAC)
#include "components/spellcheck/browser/spellcheck_platform.h"
@ -208,6 +211,31 @@ void CefBrowserHostBase::SetFocusInternal(bool focus) {
platform_delegate_->SetFocus(false);
}
void CefBrowserHostBase::RunFileDialog(
FileDialogMode mode,
const CefString& title,
const CefString& default_file_path,
const std::vector<CefString>& accept_filters,
CefRefPtr<CefRunFileDialogCallback> callback) {
DCHECK(callback);
if (!CEF_CURRENTLY_ON_UIT()) {
CEF_POST_TASK(CEF_UIT, base::BindOnce(&CefBrowserHostBase::RunFileDialog,
this, mode, title, default_file_path,
accept_filters, callback));
return;
}
if (!callback || !EnsureFileDialogManager()) {
LOG(ERROR) << "File dialog canceled due to invalid state.";
if (callback)
callback->OnFileDialogDismissed({});
return;
}
file_dialog_manager_->RunFileDialog(mode, title, default_file_path,
accept_filters, callback);
}
void CefBrowserHostBase::StartDownload(const CefString& url) {
if (!CEF_CURRENTLY_ON_UIT()) {
CEF_POST_TASK(
@ -805,6 +833,45 @@ void CefBrowserHostBase::ViewText(const std::string& text) {
platform_delegate_->ViewText(text);
}
void CefBrowserHostBase::RunFileChooserForBrowser(
const blink::mojom::FileChooserParams& params,
CefFileDialogManager::RunFileChooserCallback callback) {
if (!EnsureFileDialogManager()) {
LOG(ERROR) << "File dialog canceled due to invalid state.";
std::move(callback).Run({});
return;
}
file_dialog_manager_->RunFileChooser(params, std::move(callback));
}
void CefBrowserHostBase::RunSelectFile(
ui::SelectFileDialog::Listener* listener,
std::unique_ptr<ui::SelectFilePolicy> policy,
ui::SelectFileDialog::Type type,
const std::u16string& title,
const base::FilePath& default_path,
const ui::SelectFileDialog::FileTypeInfo* file_types,
int file_type_index,
const base::FilePath::StringType& default_extension,
gfx::NativeWindow owning_window,
void* params) {
if (!EnsureFileDialogManager()) {
LOG(ERROR) << "File dialog canceled due to invalid state.";
listener->FileSelectionCanceled(params);
return;
}
file_dialog_manager_->RunSelectFile(listener, std::move(policy), type, title,
default_path, file_types, file_type_index,
default_extension, owning_window, params);
}
void CefBrowserHostBase::SelectFileListenerDestroyed(
ui::SelectFileDialog::Listener* listener) {
if (file_dialog_manager_) {
file_dialog_manager_->SelectFileListenerDestroyed(listener);
}
}
bool CefBrowserHostBase::MaybeAllowNavigation(
content::RenderFrameHost* opener,
bool is_guest_view,
@ -833,6 +900,13 @@ void CefBrowserHostBase::OnBeforeClose() {
void CefBrowserHostBase::OnBrowserDestroyed() {
CEF_REQUIRE_UIT();
// Destroy any platform constructs.
if (file_dialog_manager_) {
file_dialog_manager_->Destroy();
file_dialog_manager_.reset();
}
for (auto& observer : observers_)
observer.OnBrowserDestroyed(this);
}
@ -878,13 +952,36 @@ CefRefPtr<CefBrowserView> CefBrowserHostBase::GetBrowserView() const {
return nullptr;
}
gfx::NativeWindow CefBrowserHostBase::GetTopLevelNativeWindow() const {
CEF_REQUIRE_UIT();
// Windowless browsers always return nullptr from GetTopLevelNativeWindow().
if (!IsWindowless()) {
auto web_contents = GetWebContents();
if (web_contents) {
return web_contents->GetTopLevelNativeWindow();
}
}
return gfx::NativeWindow();
}
bool CefBrowserHostBase::IsFocused() const {
CEF_REQUIRE_UIT();
auto web_contents = GetWebContents();
if (web_contents) {
return static_cast<content::RenderFrameHostImpl*>(
web_contents->GetMainFrame())
->IsFocused();
}
return false;
}
bool CefBrowserHostBase::EnsureDevToolsManager() {
CEF_REQUIRE_UIT();
if (!contents_delegate_->web_contents())
return false;
if (!devtools_manager_) {
devtools_manager_.reset(new CefDevToolsManager(this));
devtools_manager_ = std::make_unique<CefDevToolsManager>(this);
}
return true;
}
@ -904,3 +1001,14 @@ void CefBrowserHostBase::InitializeDevToolsRegistrationOnUIThread(
return;
devtools_manager_->InitializeRegistrationOnUIThread(registration);
}
bool CefBrowserHostBase::EnsureFileDialogManager() {
CEF_REQUIRE_UIT();
if (!contents_delegate_->web_contents())
return false;
if (!file_dialog_manager_) {
file_dialog_manager_ = std::make_unique<CefFileDialogManager>(this);
}
return true;
}

View File

@ -13,6 +13,7 @@
#include "libcef/browser/browser_info.h"
#include "libcef/browser/browser_platform_delegate.h"
#include "libcef/browser/devtools/devtools_manager.h"
#include "libcef/browser/file_dialog_manager.h"
#include "libcef/browser/frame_host_impl.h"
#include "libcef/browser/request_context_impl.h"
@ -156,6 +157,11 @@ class CefBrowserHostBase : public CefBrowserHost,
CefRefPtr<CefRequestContext> GetRequestContext() override;
bool HasView() override;
void SetFocus(bool focus) override;
void RunFileDialog(FileDialogMode mode,
const CefString& title,
const CefString& default_file_path,
const std::vector<CefString>& accept_filters,
CefRefPtr<CefRunFileDialogCallback> callback) override;
void StartDownload(const CefString& url) override;
void DownloadImage(const CefString& image_url,
bool is_favicon,
@ -234,6 +240,22 @@ class CefBrowserHostBase : public CefBrowserHost,
virtual void OnSetFocus(cef_focus_source_t source) = 0;
void ViewText(const std::string& text);
// Calls CefFileDialogManager methods.
void RunFileChooserForBrowser(
const blink::mojom::FileChooserParams& params,
CefFileDialogManager::RunFileChooserCallback callback);
void RunSelectFile(ui::SelectFileDialog::Listener* listener,
std::unique_ptr<ui::SelectFilePolicy> policy,
ui::SelectFileDialog::Type type,
const std::u16string& title,
const base::FilePath& default_path,
const ui::SelectFileDialog::FileTypeInfo* file_types,
int file_type_index,
const base::FilePath::StringType& default_extension,
gfx::NativeWindow owning_window,
void* params);
void SelectFileListenerDestroyed(ui::SelectFileDialog::Listener* listener);
// Called from CefBrowserInfoManager::MaybeAllowNavigation.
virtual bool MaybeAllowNavigation(content::RenderFrameHost* opener,
bool is_guest_view,
@ -269,13 +291,27 @@ class CefBrowserHostBase : public CefBrowserHost,
}
// Returns the Widget owner for the browser window. Only used with windowed
// rendering.
// browsers.
views::Widget* GetWindowWidget() const;
// Returns the BrowserView associated with this browser. Only used with Views-
// based browsers.
CefRefPtr<CefBrowserView> GetBrowserView() const;
// Returns the top-level native window for this browser. With windowed
// browsers this will be an aura::Window* on Aura platforms (Windows/Linux)
// and an NSWindow wrapper object from native_widget_types.h on MacOS. With
// windowless browsers this method will always return an empty value.
gfx::NativeWindow GetTopLevelNativeWindow() const;
// Returns true if this browser is currently focused. A browser is considered
// focused when the top-level RenderFrameHost is in the parent chain of the
// currently focused RFH within the frame tree. In addition, its associated
// RenderWidgetHost must also be focused. With windowed browsers only one
// browser should be focused at a time. With windowless browsers this relies
// on the client to properly configure focus state.
bool IsFocused() const;
protected:
bool EnsureDevToolsManager();
void InitializeDevToolsRegistrationOnUIThread(
@ -286,6 +322,9 @@ class CefBrowserHostBase : public CefBrowserHost,
void SetFocusInternal(bool focus);
// Create the CefFileDialogManager if it doesn't already exist.
bool EnsureFileDialogManager();
// Thread-safe members.
CefBrowserSettings settings_;
CefRefPtr<CefClient> client_;
@ -301,6 +340,9 @@ class CefBrowserHostBase : public CefBrowserHost,
// Only accessed on the UI thread.
base::ObserverList<Observer> observers_;
// Used for creating and managing file dialogs.
std::unique_ptr<CefFileDialogManager> file_dialog_manager_;
// Volatile state accessed from multiple threads. All access must be protected
// by |state_lock_|.
base::Lock state_lock_;

View File

@ -223,12 +223,6 @@ CefEventHandle CefBrowserPlatformDelegate::GetEventHandle(
return kNullEventHandle;
}
std::unique_ptr<CefFileDialogRunner>
CefBrowserPlatformDelegate::CreateFileDialogRunner() {
NOTIMPLEMENTED();
return nullptr;
}
std::unique_ptr<CefJavaScriptDialogRunner>
CefBrowserPlatformDelegate::CreateJavaScriptDialogRunner() {
NOTIMPLEMENTED();

View File

@ -63,7 +63,6 @@ class Widget;
struct CefBrowserCreateParams;
class CefBrowserHostBase;
class CefFileDialogRunner;
class CefJavaScriptDialogRunner;
class CefMenuRunner;
@ -266,9 +265,6 @@ class CefBrowserPlatformDelegate {
virtual CefEventHandle GetEventHandle(
const content::NativeWebKeyboardEvent& event) const;
// Create the platform-specific file dialog runner.
virtual std::unique_ptr<CefFileDialogRunner> CreateFileDialogRunner();
// Create the platform-specific JavaScript dialog runner.
virtual std::unique_ptr<CefJavaScriptDialogRunner>
CreateJavaScriptDialogRunner();

View File

@ -186,17 +186,6 @@ void ChromeBrowserHostImpl::SetZoomLevel(double zoomLevel) {
NOTIMPLEMENTED();
}
void ChromeBrowserHostImpl::RunFileDialog(
FileDialogMode mode,
const CefString& title,
const CefString& default_file_path,
const std::vector<CefString>& accept_filters,
int selected_accept_filter,
CefRefPtr<CefRunFileDialogCallback> callback) {
NOTIMPLEMENTED();
callback->OnFileDialogDismissed(0, {});
}
void ChromeBrowserHostImpl::Print() {
if (!CEF_CURRENTLY_ON_UIT()) {
CEF_POST_TASK(CEF_UIT, base::BindOnce(&ChromeBrowserHostImpl::Print, this));

View File

@ -66,12 +66,6 @@ class ChromeBrowserHostImpl : public CefBrowserHostBase {
CefWindowHandle GetOpenerWindowHandle() override;
double GetZoomLevel() override;
void SetZoomLevel(double zoomLevel) override;
void RunFileDialog(FileDialogMode mode,
const CefString& title,
const CefString& default_file_path,
const std::vector<CefString>& accept_filters,
int selected_accept_filter,
CefRefPtr<CefRunFileDialogCallback> callback) override;
void Print() override;
void PrintToPDF(const CefString& path,
const CefPdfPrintSettings& settings,

View File

@ -6,6 +6,7 @@
#include "libcef/browser/chrome/chrome_context_menu_handler.h"
#include "libcef/browser/context.h"
#include "libcef/browser/file_dialog_runner.h"
#include "libcef/browser/net/chrome_scheme_handler.h"
#include "base/task/post_task.h"
@ -41,4 +42,5 @@ void ChromeBrowserMainExtraPartsCef::PreMainMessageLoopRun() {
scheme::RegisterWebUIControllerFactory();
context_menu::RegisterMenuCreatedCallback();
file_dialog_runner::RegisterFactory();
}

View File

@ -106,7 +106,7 @@ void CefDevToolsFileManager::Save(const std::string& url,
}
}
CefFileDialogRunner::FileChooserParams params;
blink::mojom::FileChooserParams params;
params.mode = blink::mojom::FileChooserParams::Mode::kSave;
if (!initial_path.empty()) {
params.default_file_name = initial_path;
@ -115,7 +115,7 @@ void CefDevToolsFileManager::Save(const std::string& url,
}
}
browser_impl_->RunFileChooser(
browser_impl_->RunFileChooserForBrowser(
params,
base::BindOnce(&CefDevToolsFileManager::SaveAsDialogDismissed,
weak_factory_.GetWeakPtr(), url, content,
@ -127,7 +127,6 @@ void CefDevToolsFileManager::SaveAsDialogDismissed(
const std::string& content,
SaveCallback saveCallback,
CancelCallback cancelCallback,
int selected_accept_filter,
const std::vector<base::FilePath>& file_paths) {
if (file_paths.size() == 1) {
SaveAsFileSelected(url, content, std::move(saveCallback), file_paths[0]);

View File

@ -49,7 +49,6 @@ class CefDevToolsFileManager {
const std::string& content,
SaveCallback saveCallback,
CancelCallback cancelCallback,
int selected_accept_filter,
const std::vector<base::FilePath>& file_paths);
void SaveAsFileSelected(const std::string& url,
const std::string& content,

View File

@ -136,7 +136,7 @@ class CefBeforeDownloadCallbackImpl : public CefBeforeDownloadCallback {
if (browser.get()) {
handled = true;
CefFileDialogRunner::FileChooserParams params;
blink::mojom::FileChooserParams params;
params.mode = blink::mojom::FileChooserParams::Mode::kSave;
if (!suggested_path.empty()) {
params.default_file_name = suggested_path;
@ -146,7 +146,7 @@ class CefBeforeDownloadCallbackImpl : public CefBeforeDownloadCallback {
}
}
browser->RunFileChooser(
browser->RunFileChooserForBrowser(
params,
base::BindOnce(
&CefBeforeDownloadCallbackImpl::ChooseDownloadPathCallback,
@ -166,7 +166,6 @@ class CefBeforeDownloadCallbackImpl : public CefBeforeDownloadCallback {
static void ChooseDownloadPathCallback(
content::DownloadTargetCallback callback,
int selected_accept_filter,
const std::vector<base::FilePath>& file_paths) {
DCHECK_LE(file_paths.size(), (size_t)1);

View File

@ -4,18 +4,14 @@
#include "libcef/browser/extensions/api/file_system/cef_file_system_delegate.h"
#include "libcef/browser/alloy/alloy_dialog_util.h"
#include "apps/saved_files_service.h"
#include "base/callback.h"
#include "base/callback_forward.h"
#include "base/files/file_path.h"
#include "chrome/browser/extensions/api/file_system/file_entry_picker.h"
#include "chrome/grit/generated_resources.h"
#include "content/public/browser/web_contents.h"
#include "extensions/common/api/file_system.h"
#include "extensions/common/extension.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
using blink::mojom::FileChooserParams;
namespace extensions {
namespace cef {
@ -46,61 +42,17 @@ bool CefFileSystemDelegate::ShowSelectFileDialog(
return false;
}
absl::optional<FileChooserParams::Mode> mode;
switch (type) {
case ui::SelectFileDialog::Type::SELECT_UPLOAD_FOLDER:
mode = FileChooserParams::Mode::kUploadFolder;
break;
case ui::SelectFileDialog::Type::SELECT_SAVEAS_FILE:
mode = FileChooserParams::Mode::kSave;
break;
case ui::SelectFileDialog::Type::SELECT_OPEN_FILE:
mode = FileChooserParams::Mode::kOpen;
break;
case ui::SelectFileDialog::Type::SELECT_OPEN_MULTI_FILE:
mode = FileChooserParams::Mode::kOpenMultiple;
break;
default:
NOTIMPLEMENTED();
return false;
}
FileChooserParams params;
params.mode = *mode;
params.default_file_name = default_path;
if (file_types) {
// A list of allowed extensions. For example, it might be
// { { "htm", "html" }, { "txt" } }
for (auto& vec : file_types->extensions) {
for (auto& ext : vec) {
params.accept_types.push_back(
alloy::FilePathTypeToString16(FILE_PATH_LITERAL(".") + ext));
}
}
}
alloy::RunFileChooser(
web_contents, params,
base::BindOnce(&CefFileSystemDelegate::FileDialogDismissed,
weak_ptr_factory_.GetWeakPtr(),
std::move(files_selected_callback),
std::move(file_selection_canceled_callback)));
// The file picker will hold a reference to the ExtensionFunction
// instance, preventing its destruction (and subsequent sending of the
// function response) until the user has selected a file or cancelled the
// picker. At that point, the picker will delete itself, which will also free
// the function instance.
new FileEntryPicker(web_contents, default_path, *file_types, type,
std::move(files_selected_callback),
std::move(file_selection_canceled_callback));
return true;
}
void CefFileSystemDelegate::FileDialogDismissed(
FileSystemDelegate::FilesSelectedCallback files_selected_callback,
base::OnceClosure file_selection_canceled_callback,
int selected_accept_filter,
const std::vector<base::FilePath>& file_paths) {
if (!file_paths.empty()) {
std::move(files_selected_callback).Run(file_paths);
} else {
std::move(file_selection_canceled_callback).Run();
}
}
void CefFileSystemDelegate::ConfirmSensitiveDirectoryAccess(
bool has_write_permission,
const std::u16string& app_name,

View File

@ -10,7 +10,6 @@
#include "base/callback.h"
#include "base/compiler_specific.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "extensions/browser/api/execute_code_function.h"
#include "extensions/browser/api/file_system/file_system_delegate.h"
#include "extensions/browser/extension_function.h"
@ -51,15 +50,6 @@ class CefFileSystemDelegate : public FileSystemDelegate {
int GetDescriptionIdForAcceptType(const std::string& accept_type) override;
SavedFilesServiceInterface* GetSavedFilesService(
content::BrowserContext* browser_context) override;
private:
void FileDialogDismissed(
FileSystemDelegate::FilesSelectedCallback files_selected_callback,
base::OnceClosure file_selection_canceled_callback,
int selected_accept_filter,
const std::vector<base::FilePath>& file_paths);
base::WeakPtrFactory<CefFileSystemDelegate> weak_ptr_factory_{this};
};
} // namespace cef

View File

@ -102,11 +102,6 @@ CefEventHandle CefBrowserPlatformDelegateBackground::GetEventHandle(
return native_delegate_->GetEventHandle(event);
}
std::unique_ptr<CefFileDialogRunner>
CefBrowserPlatformDelegateBackground::CreateFileDialogRunner() {
return native_delegate_->CreateFileDialogRunner();
}
std::unique_ptr<CefJavaScriptDialogRunner>
CefBrowserPlatformDelegateBackground::CreateJavaScriptDialogRunner() {
return native_delegate_->CreateJavaScriptDialogRunner();

View File

@ -40,7 +40,6 @@ class CefBrowserPlatformDelegateBackground
const content::NativeWebKeyboardEvent& event) override;
CefEventHandle GetEventHandle(
const content::NativeWebKeyboardEvent& event) const override;
std::unique_ptr<CefFileDialogRunner> CreateFileDialogRunner() override;
std::unique_ptr<CefJavaScriptDialogRunner> CreateJavaScriptDialogRunner()
override;
std::unique_ptr<CefMenuRunner> CreateMenuRunner() override;

View File

@ -8,18 +8,22 @@
#include <utility>
#include "include/cef_dialog_handler.h"
#include "libcef/browser/alloy/alloy_browser_host_impl.h"
#include "libcef/browser/browser_host_base.h"
#include "libcef/browser/context.h"
#include "libcef/browser/thread_util.h"
#include "chrome/browser/file_select_helper.h"
#include "content/public/browser/file_select_listener.h"
#include "content/public/browser/render_frame_host.h"
#include "net/base/directory_lister.h"
#include "ui/shell_dialogs/select_file_policy.h"
using blink::mojom::FileChooserParams;
namespace {
class CefFileDialogCallbackImpl : public CefFileDialogCallback {
public:
using CallbackType = CefFileDialogRunner::RunFileChooserCallback;
using CallbackType = CefFileDialogManager::RunFileChooserCallback;
explicit CefFileDialogCallbackImpl(CallbackType callback)
: callback_(std::move(callback)) {}
@ -37,8 +41,7 @@ class CefFileDialogCallbackImpl : public CefFileDialogCallback {
}
}
void Continue(int selected_accept_filter,
const std::vector<CefString>& file_paths) override {
void Continue(const std::vector<CefString>& file_paths) override {
if (CEF_CURRENTLY_ON_UIT()) {
if (!callback_.is_null()) {
std::vector<base::FilePath> vec;
@ -47,12 +50,12 @@ class CefFileDialogCallbackImpl : public CefFileDialogCallback {
for (; it != file_paths.end(); ++it)
vec.push_back(base::FilePath(*it));
}
std::move(callback_).Run(selected_accept_filter, vec);
std::move(callback_).Run(vec);
}
} else {
CEF_POST_TASK(CEF_UIT,
base::BindOnce(&CefFileDialogCallbackImpl::Continue, this,
selected_accept_filter, file_paths));
file_paths));
}
}
@ -73,7 +76,7 @@ class CefFileDialogCallbackImpl : public CefFileDialogCallback {
static void CancelNow(CallbackType callback) {
CEF_REQUIRE_UIT();
std::vector<base::FilePath> file_paths;
std::move(callback).Run(0, file_paths);
std::move(callback).Run(file_paths);
}
CallbackType callback_;
@ -82,77 +85,210 @@ class CefFileDialogCallbackImpl : public CefFileDialogCallback {
};
void RunFileDialogDismissed(CefRefPtr<CefRunFileDialogCallback> callback,
int selected_accept_filter,
const std::vector<base::FilePath>& file_paths) {
std::vector<CefString> paths;
if (file_paths.size() > 0) {
for (size_t i = 0; i < file_paths.size(); ++i)
paths.push_back(file_paths[i].value());
}
callback->OnFileDialogDismissed(selected_accept_filter, paths);
callback->OnFileDialogDismissed(paths);
}
class UploadFolderHelper
: public net::DirectoryLister::DirectoryListerDelegate {
public:
explicit UploadFolderHelper(
CefFileDialogRunner::RunFileChooserCallback callback)
: callback_(std::move(callback)) {}
// Based on net/base/filename_util_internal.cc FilePathToString16().
std::u16string FilePathTypeToString16(const base::FilePath::StringType& str) {
std::u16string result;
#if BUILDFLAG(IS_WIN)
result.assign(str.begin(), str.end());
#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
if (!str.empty()) {
base::UTF8ToUTF16(str.c_str(), str.size(), &result);
}
#endif
return result;
}
UploadFolderHelper(const UploadFolderHelper&) = delete;
UploadFolderHelper& operator=(const UploadFolderHelper&) = delete;
FileChooserParams SelectFileToFileChooserParams(
ui::SelectFileDialog::Type type,
const std::u16string& title,
const base::FilePath& default_path,
const ui::SelectFileDialog::FileTypeInfo* file_types) {
FileChooserParams params;
~UploadFolderHelper() override {
if (!callback_.is_null()) {
if (CEF_CURRENTLY_ON_UIT()) {
CancelNow(std::move(callback_));
} else {
CEF_POST_TASK(CEF_UIT, base::BindOnce(&UploadFolderHelper::CancelNow,
std::move(callback_)));
absl::optional<FileChooserParams::Mode> mode;
switch (type) {
case ui::SelectFileDialog::Type::SELECT_UPLOAD_FOLDER:
mode = FileChooserParams::Mode::kUploadFolder;
break;
case ui::SelectFileDialog::Type::SELECT_SAVEAS_FILE:
mode = FileChooserParams::Mode::kSave;
break;
case ui::SelectFileDialog::Type::SELECT_OPEN_FILE:
mode = FileChooserParams::Mode::kOpen;
break;
case ui::SelectFileDialog::Type::SELECT_OPEN_MULTI_FILE:
mode = FileChooserParams::Mode::kOpenMultiple;
break;
default:
NOTIMPLEMENTED();
return params;
}
params.mode = *mode;
params.title = title;
params.default_file_name = default_path;
// Note that this translation will lose any mime-type based filters that
// may have existed in the original FileChooserParams::accept_types if this
// dialog was created via FileSelectHelper::RunFileChooser.
if (file_types) {
// A list of allowed extensions. For example, it might be
// { { "htm", "html" }, { "txt" } }
for (auto& vec : file_types->extensions) {
for (auto& ext : vec) {
params.accept_types.push_back(
FilePathTypeToString16(FILE_PATH_LITERAL(".") + ext));
}
}
}
void OnListFile(
const net::DirectoryLister::DirectoryListerData& data) override {
CEF_REQUIRE_UIT();
if (!data.info.IsDirectory())
select_files_.push_back(data.path);
}
return params;
}
void OnListDone(int error) override {
CEF_REQUIRE_UIT();
if (!callback_.is_null()) {
std::move(callback_).Run(0, select_files_);
}
}
class CefFileSelectListener : public content::FileSelectListener {
public:
using CallbackType = CefFileDialogManager::RunFileChooserCallback;
explicit CefFileSelectListener(CallbackType callback)
: callback_(std::move(callback)) {}
private:
static void CancelNow(CefFileDialogRunner::RunFileChooserCallback callback) {
CEF_REQUIRE_UIT();
std::vector<base::FilePath> file_paths;
std::move(callback).Run(0, file_paths);
~CefFileSelectListener() override = default;
void FileSelected(std::vector<blink::mojom::FileChooserFileInfoPtr> files,
const base::FilePath& base_dir,
FileChooserParams::Mode mode) override {
std::vector<base::FilePath> paths;
if (mode == FileChooserParams::Mode::kUploadFolder) {
if (!base_dir.empty()) {
paths.push_back(base_dir);
}
} else if (!files.empty()) {
for (auto& file : files) {
if (file->is_native_file()) {
paths.push_back(file->get_native_file()->file_path);
} else {
NOTIMPLEMENTED();
}
}
}
std::move(callback_).Run(paths);
}
CefFileDialogRunner::RunFileChooserCallback callback_;
std::vector<base::FilePath> select_files_;
void FileSelectionCanceled() override { std::move(callback_).Run({}); }
CallbackType callback_;
};
} // namespace
CefFileDialogManager::CefFileDialogManager(
AlloyBrowserHostImpl* browser,
std::unique_ptr<CefFileDialogRunner> runner)
: browser_(browser),
runner_(std::move(runner)),
file_chooser_pending_(false),
weak_ptr_factory_(this) {}
class CefSelectFileDialogListener : public ui::SelectFileDialog::Listener {
public:
CefSelectFileDialogListener(ui::SelectFileDialog::Listener* listener,
void* params,
base::OnceClosure callback)
: listener_(listener), params_(params), callback_(std::move(callback)) {}
CefFileDialogManager::~CefFileDialogManager() {}
CefSelectFileDialogListener(const CefSelectFileDialogListener&) = delete;
CefSelectFileDialogListener& operator=(const CefSelectFileDialogListener&) =
delete;
void Cancel(bool listener_destroyed) {
if (executing_) {
// We're likely still on the stack. Do nothing and wait for Destroy().
return;
}
if (listener_destroyed) {
// Don't execute the listener.
Destroy();
} else {
FileSelectionCanceled(params_);
}
}
ui::SelectFileDialog::Listener* listener() const { return listener_; }
private:
~CefSelectFileDialogListener() override = default;
void FileSelected(const base::FilePath& path,
int index,
void* params) override {
DCHECK_EQ(params, params_);
executing_ = true;
listener_->FileSelected(path, index, params);
Destroy();
}
void FileSelectedWithExtraInfo(const ui::SelectedFileInfo& file,
int index,
void* params) override {
DCHECK_EQ(params, params_);
executing_ = true;
listener_->FileSelectedWithExtraInfo(file, index, params);
Destroy();
}
void MultiFilesSelected(const std::vector<base::FilePath>& files,
void* params) override {
DCHECK_EQ(params, params_);
executing_ = true;
listener_->MultiFilesSelected(files, params);
Destroy();
}
void MultiFilesSelectedWithExtraInfo(
const std::vector<ui::SelectedFileInfo>& files,
void* params) override {
DCHECK_EQ(params, params_);
executing_ = true;
listener_->MultiFilesSelectedWithExtraInfo(files, params);
Destroy();
}
void FileSelectionCanceled(void* params) override {
DCHECK_EQ(params, params_);
executing_ = true;
listener_->FileSelectionCanceled(params);
Destroy();
}
void Destroy() {
std::move(callback_).Run();
delete this;
}
ui::SelectFileDialog::Listener* const listener_;
void* const params_;
base::OnceClosure callback_;
// Used to avoid re-entrancy from Cancel().
bool executing_ = false;
};
CefFileDialogManager::CefFileDialogManager(CefBrowserHostBase* browser)
: browser_(browser) {}
CefFileDialogManager::~CefFileDialogManager() = default;
void CefFileDialogManager::Destroy() {
DCHECK(!file_chooser_pending_);
runner_.reset(nullptr);
if (dialog_listener_) {
// Cancel the listener and delete related objects.
SelectFileDoneByListenerCallback(/*listener_destroyed=*/false);
}
DCHECK(!dialog_);
DCHECK(!dialog_listener_);
DCHECK(active_listeners_.empty());
}
void CefFileDialogManager::RunFileDialog(
@ -160,14 +296,13 @@ void CefFileDialogManager::RunFileDialog(
const CefString& title,
const CefString& default_file_path,
const std::vector<CefString>& accept_filters,
int selected_accept_filter,
CefRefPtr<CefRunFileDialogCallback> callback) {
DCHECK(callback.get());
if (!callback.get())
return;
CefFileDialogRunner::FileChooserParams params;
switch (mode & FILE_DIALOG_TYPE_MASK) {
blink::mojom::FileChooserParams params;
switch (mode) {
case FILE_DIALOG_OPEN:
params.mode = blink::mojom::FileChooserParams::Mode::kOpen;
break;
@ -182,12 +317,6 @@ void CefFileDialogManager::RunFileDialog(
break;
}
DCHECK_GE(selected_accept_filter, 0);
params.selected_accept_filter = selected_accept_filter;
params.overwriteprompt = !!(mode & FILE_DIALOG_OVERWRITEPROMPT_FLAG);
params.hidereadonly = !!(mode & FILE_DIALOG_HIDEREADONLY_FLAG);
params.title = title;
if (!default_file_path.empty())
params.default_file_name = base::FilePath(default_file_path);
@ -202,55 +331,145 @@ void CefFileDialogManager::RunFileDialog(
}
void CefFileDialogManager::RunFileChooser(
scoped_refptr<content::FileSelectListener> listener,
const blink::mojom::FileChooserParams& params) {
const blink::mojom::FileChooserParams& params,
RunFileChooserCallback callback) {
CEF_REQUIRE_UIT();
CefFileDialogRunner::FileChooserParams cef_params;
static_cast<blink::mojom::FileChooserParams&>(cef_params) = params;
CefFileDialogRunner::RunFileChooserCallback callback;
if (params.mode == blink::mojom::FileChooserParams::Mode::kUploadFolder) {
callback = base::BindOnce(
&CefFileDialogManager::OnRunFileChooserUploadFolderDelegateCallback,
weak_ptr_factory_.GetWeakPtr(), params.mode, listener);
} else {
callback =
base::BindOnce(&CefFileDialogManager::OnRunFileChooserDelegateCallback,
weak_ptr_factory_.GetWeakPtr(), params.mode, listener);
}
RunFileChooserInternal(cef_params, std::move(callback));
}
void CefFileDialogManager::RunFileChooser(
const CefFileDialogRunner::FileChooserParams& params,
CefFileDialogRunner::RunFileChooserCallback callback) {
CefFileDialogRunner::RunFileChooserCallback host_callback =
base::BindOnce(&CefFileDialogManager::OnRunFileChooserCallback,
weak_ptr_factory_.GetWeakPtr(), std::move(callback));
RunFileChooserInternal(params, std::move(host_callback));
}
void CefFileDialogManager::RunFileChooserInternal(
const CefFileDialogRunner::FileChooserParams& params,
CefFileDialogRunner::RunFileChooserCallback callback) {
CEF_REQUIRE_UIT();
if (file_chooser_pending_) {
// Dismiss the new dialog immediately.
std::move(callback).Run(0, std::vector<base::FilePath>());
// Execute the delegate with the most exact version of |params|. If not
// handled here there will be another call to the delegate from RunSelectFile.
// It might be better to execute the delegate only the single time here, but
// we don't currently have sufficient state in RunSelectFile to know that the
// delegate has already been executed.
callback = MaybeRunDelegate(params, std::move(callback));
if (callback.is_null()) {
// The delegate kept the callback.
return;
}
file_chooser_pending_ = true;
FileChooserParams new_params = params;
bool handled = false;
// Make sure we get native files in CefFileSelectListener.
new_params.need_local_path = true;
if (browser_->client().get()) {
CefRefPtr<CefDialogHandler> handler =
browser_->client()->GetDialogHandler();
if (handler.get()) {
// Requirements of FileSelectHelper.
if (params.mode != FileChooserParams::Mode::kSave) {
new_params.default_file_name = base::FilePath();
} else {
new_params.default_file_name = new_params.default_file_name.BaseName();
}
// FileSelectHelper is usually only used for renderer-initiated dialogs via
// WebContentsDelegate::RunFileChooser. We choose to use it here instead of
// calling ui::SelectFileDialog::Create directly because it provides some nice
// functionality related to default dialog settings and filter list
// generation. We customize the behavior slightly for non-renderer-initiated
// dialogs by passing the |run_from_cef=true| flag. FileSelectHelper uses
// ui::SelectFileDialog::Create internally and that call will be intercepted
// by CefSelectFileDialogFactory, resulting in call to RunSelectFile below.
// See related comments on CefSelectFileDialogFactory.
FileSelectHelper::RunFileChooser(
browser_->GetWebContents()->GetMainFrame(),
base::MakeRefCounted<CefFileSelectListener>(std::move(callback)),
new_params, /*run_from_cef=*/true);
}
void CefFileDialogManager::RunSelectFile(
ui::SelectFileDialog::Listener* listener,
std::unique_ptr<ui::SelectFilePolicy> policy,
ui::SelectFileDialog::Type type,
const std::u16string& title,
const base::FilePath& default_path,
const ui::SelectFileDialog::FileTypeInfo* file_types,
int file_type_index,
const base::FilePath::StringType& default_extension,
gfx::NativeWindow owning_window,
void* params) {
CEF_REQUIRE_UIT();
active_listeners_.insert(listener);
// This will not be an exact representation of the original params.
auto chooser_params =
SelectFileToFileChooserParams(type, title, default_path, file_types);
auto callback =
base::BindOnce(&CefFileDialogManager::SelectFileDoneByDelegateCallback,
weak_ptr_factory_.GetWeakPtr(), base::Unretained(listener),
base::Unretained(params));
callback = MaybeRunDelegate(chooser_params, std::move(callback));
if (callback.is_null()) {
// The delegate kept the callback.
return;
}
if (dialog_) {
LOG(ERROR) << "Multiple simultaneous dialogs are not supported; "
"canceling the file dialog";
std::move(callback).Run({});
return;
}
#if BUILDFLAG(IS_LINUX)
// We can't use GtkUi in combination with multi-threaded-message-loop because
// Chromium's GTK implementation doesn't use GDK threads.
if (!!CefContext::Get()->settings().multi_threaded_message_loop) {
LOG(ERROR) << "Default dialog implementation is not available; "
"canceling the file dialog";
std::move(callback).Run({});
return;
}
#endif
// |callback| is no longer used at this point.
callback.Reset();
DCHECK(!dialog_listener_);
// This object will delete itself.
dialog_listener_ = new CefSelectFileDialogListener(
listener, params,
base::BindOnce(&CefFileDialogManager::SelectFileDoneByListenerCallback,
weak_ptr_factory_.GetWeakPtr(),
/*listener_destroyed=*/false));
// This call will not be intercepted by CefSelectFileDialogFactory due to the
// |run_from_cef=true| flag.
// See related comments on CefSelectFileDialogFactory.
dialog_ = ui::SelectFileDialog::Create(dialog_listener_, std::move(policy),
/*run_from_cef=*/true);
// With windowless rendering use the parent handle specified by the client.
if (browser_->IsWindowless()) {
DCHECK(!owning_window);
dialog_->set_owning_widget(browser_->GetWindowHandle());
}
dialog_->SelectFile(type, title, default_path, file_types, file_type_index,
default_extension, owning_window, params);
}
void CefFileDialogManager::SelectFileListenerDestroyed(
ui::SelectFileDialog::Listener* listener) {
CEF_REQUIRE_UIT();
DCHECK(listener);
// This notification will arrive from whomever owns |listener|, so we don't
// want to execute any |listener| methods after this point.
if (dialog_listener_ && listener == dialog_listener_->listener()) {
// Cancel the currently active dialog.
SelectFileDoneByListenerCallback(/*listener_destroyed=*/true);
} else {
// Any future SelectFileDoneByDelegateCallback call for |listener| becomes a
// no-op.
active_listeners_.erase(listener);
}
}
CefFileDialogManager::RunFileChooserCallback
CefFileDialogManager::MaybeRunDelegate(
const blink::mojom::FileChooserParams& params,
RunFileChooserCallback callback) {
if (auto client = browser_->client()) {
if (auto handler = browser_->client()->GetDialogHandler()) {
int mode = FILE_DIALOG_OPEN;
switch (params.mode) {
case blink::mojom::FileChooserParams::Mode::kOpen:
@ -270,11 +489,6 @@ void CefFileDialogManager::RunFileChooserInternal(
break;
}
if (params.overwriteprompt)
mode |= FILE_DIALOG_OVERWRITEPROMPT_FLAG;
if (params.hidereadonly)
mode |= FILE_DIALOG_HIDEREADONLY_FLAG;
std::vector<std::u16string>::const_iterator it;
std::vector<CefString> accept_filters;
@ -284,10 +498,9 @@ void CefFileDialogManager::RunFileChooserInternal(
CefRefPtr<CefFileDialogCallbackImpl> callbackImpl(
new CefFileDialogCallbackImpl(std::move(callback)));
handled = handler->OnFileDialog(
const bool handled = handler->OnFileDialog(
browser_, static_cast<cef_file_dialog_mode_t>(mode), params.title,
params.default_file_name.value(), accept_filters,
params.selected_accept_filter, callbackImpl.get());
params.default_file_name.value(), accept_filters, callbackImpl.get());
if (!handled) {
// May return nullptr if the client has already executed the callback.
callback = callbackImpl->Disconnect();
@ -295,82 +508,57 @@ void CefFileDialogManager::RunFileChooserInternal(
}
}
if (!handled && !callback.is_null()) {
if (runner_.get()) {
runner_->Run(browser_, params, std::move(callback));
} else {
LOG(WARNING) << "No file dialog runner available for this platform";
std::move(callback).Run(0, std::vector<base::FilePath>());
}
}
return callback;
}
void CefFileDialogManager::OnRunFileChooserCallback(
CefFileDialogRunner::RunFileChooserCallback callback,
int selected_accept_filter,
const std::vector<base::FilePath>& file_paths) {
void CefFileDialogManager::SelectFileDoneByDelegateCallback(
ui::SelectFileDialog::Listener* listener,
void* params,
const std::vector<base::FilePath>& paths) {
CEF_REQUIRE_UIT();
Cleanup();
// The listener may already be gone. This can occur if the client holds a
// RunFileChooserCallback past the call to SelectFileListenerDestroyed().
if (active_listeners_.find(listener) == active_listeners_.end())
return;
// Execute the callback asynchronously.
CEF_POST_TASK(CEF_UIT, base::BindOnce(std::move(callback),
selected_accept_filter, file_paths));
}
active_listeners_.erase(listener);
void CefFileDialogManager::OnRunFileChooserUploadFolderDelegateCallback(
const blink::mojom::FileChooserParams::Mode mode,
scoped_refptr<content::FileSelectListener> listener,
int selected_accept_filter,
const std::vector<base::FilePath>& file_paths) {
CEF_REQUIRE_UIT();
DCHECK_EQ(mode, blink::mojom::FileChooserParams::Mode::kUploadFolder);
if (file_paths.size() == 0) {
// Client canceled the file chooser.
OnRunFileChooserDelegateCallback(mode, listener, selected_accept_filter,
file_paths);
if (paths.empty()) {
listener->FileSelectionCanceled(params);
} else if (paths.size() == 1) {
listener->FileSelected(paths[0], /*index=*/0, params);
} else {
lister_.reset(new net::DirectoryLister(
file_paths[0], net::DirectoryLister::NO_SORT_RECURSIVE,
new UploadFolderHelper(base::BindOnce(
&CefFileDialogManager::OnRunFileChooserDelegateCallback,
weak_ptr_factory_.GetWeakPtr(), mode, listener))));
lister_->Start();
listener->MultiFilesSelected(paths, params);
}
// |listener| is likely deleted at this point.
}
void CefFileDialogManager::OnRunFileChooserDelegateCallback(
blink::mojom::FileChooserParams::Mode mode,
scoped_refptr<content::FileSelectListener> listener,
int selected_accept_filter,
const std::vector<base::FilePath>& file_paths) {
void CefFileDialogManager::SelectFileDoneByListenerCallback(
bool listener_destroyed) {
CEF_REQUIRE_UIT();
base::FilePath base_dir;
std::vector<blink::mojom::FileChooserFileInfoPtr> selected_files;
// Avoid re-entrancy of this method. CefSelectFileDialogListener callbacks to
// the delegated listener may result in an immediate call to
// SelectFileListenerDestroyed() while |dialog_listener_| is still on the
// stack, followed by another execution from
// CefSelectFileDialogListener::Destroy(). Similarly, the below call to
// Cancel() may trigger another execution from
// CefSelectFileDialogListener::Destroy().
if (!dialog_listener_)
return;
if (!file_paths.empty()) {
if (mode == blink::mojom::FileChooserParams::Mode::kUploadFolder) {
base_dir = file_paths[0].DirName();
}
DCHECK(dialog_);
DCHECK(dialog_listener_);
// Convert FilePath list to SelectedFileInfo list.
for (size_t i = 0; i < file_paths.size(); ++i) {
auto info = blink::mojom::FileChooserFileInfo::NewNativeFile(
blink::mojom::NativeFileInfo::New(file_paths[i], std::u16string()));
selected_files.push_back(std::move(info));
}
}
active_listeners_.erase(dialog_listener_->listener());
listener->FileSelected(std::move(selected_files), base_dir, mode);
// Clear |dialog_listener_| before calling Cancel() to avoid re-entrancy.
auto dialog_listener = dialog_listener_;
dialog_listener_ = nullptr;
dialog_listener->Cancel(listener_destroyed);
Cleanup();
}
void CefFileDialogManager::Cleanup() {
if (lister_)
lister_.reset();
file_chooser_pending_ = false;
// There should be no further listener callbacks after this call.
dialog_->ListenerDestroyed();
dialog_ = nullptr;
}

View File

@ -7,28 +7,25 @@
#define CEF_LIBCEF_BROWSER_FILE_DIALOG_MANAGER_H_
#pragma once
#include "include/cef_browser.h"
#include "libcef/browser/file_dialog_runner.h"
#include <memory>
#include <set>
#include "base/memory/weak_ptr.h"
#include "content/public/browser/web_contents_observer.h"
#include "include/cef_browser.h"
#include "base/memory/scoped_refptr.h"
#include "third_party/blink/public/mojom/choosers/file_chooser.mojom.h"
#include "ui/shell_dialogs/select_file_dialog.h"
namespace content {
class FileSelectListener;
class WebContents;
} // namespace content
namespace net {
class DirectoryLister;
}
class AlloyBrowserHostImpl;
class CefBrowserHostBase;
class CefSelectFileDialogListener;
class CefFileDialogManager {
public:
// |runner| may be NULL if the platform doesn't implement dialogs.
CefFileDialogManager(AlloyBrowserHostImpl* browser,
std::unique_ptr<CefFileDialogRunner> runner);
explicit CefFileDialogManager(CefBrowserHostBase* browser);
CefFileDialogManager(const CefFileDialogManager&) = delete;
CefFileDialogManager& operator=(const CefFileDialogManager&) = delete;
@ -38,70 +35,65 @@ class CefFileDialogManager {
// Delete the runner to free any platform constructs.
void Destroy();
// Called from AlloyBrowserHostImpl::RunFileChooser.
// See CefBrowserHost::RunFileDialog documentation.
// Run a file dialog with the specified parameters. See
// CefBrowserHost::RunFileDialog for usage documentation. This method should
// be called via CefBrowserHostBase::RunFileDialog.
void RunFileDialog(cef_file_dialog_mode_t mode,
const CefString& title,
const CefString& default_file_path,
const std::vector<CefString>& accept_filters,
int selected_accept_filter,
CefRefPtr<CefRunFileDialogCallback> callback);
// Called from AlloyBrowserHostImpl::RunFileChooser.
// See WebContentsDelegate::RunFileChooser documentation.
void RunFileChooser(scoped_refptr<content::FileSelectListener> listener,
const blink::mojom::FileChooserParams& params);
// The argument vector will be empty if the dialog was canceled.
using RunFileChooserCallback =
base::OnceCallback<void(const std::vector<base::FilePath>&)>;
// Run the file chooser dialog specified by |params|. Only a single dialog may
// be pending at any given time. |callback| will be executed asynchronously
// after the dialog is dismissed or if another dialog is already pending.
void RunFileChooser(const CefFileDialogRunner::FileChooserParams& params,
CefFileDialogRunner::RunFileChooserCallback callback);
// Run the file dialog specified by |params|. |callback| will be executed
// synchronously or asynchronously after the dialog is dismissed. This method
// should be called via CefBrowserHostBase::RunFileChooser.
void RunFileChooser(const blink::mojom::FileChooserParams& params,
RunFileChooserCallback callback);
// Run a ui::SelectFileDialog with the specified parameters. See
// ui::SelectFileDialog for usage documentation. This method should be called
// via CefBrowserHostBase::RunSelectFile. It will be called for all file
// dialogs after interception via CefSelectFileDialog::SelectFileImpl.
void RunSelectFile(ui::SelectFileDialog::Listener* listener,
std::unique_ptr<ui::SelectFilePolicy> policy,
ui::SelectFileDialog::Type type,
const std::u16string& title,
const base::FilePath& default_path,
const ui::SelectFileDialog::FileTypeInfo* file_types,
int file_type_index,
const base::FilePath::StringType& default_extension,
gfx::NativeWindow owning_window,
void* params);
// Must be called when the |listener| passed to RunSelectFile is destroyed.
void SelectFileListenerDestroyed(ui::SelectFileDialog::Listener* listener);
private:
void RunFileChooserInternal(
const CefFileDialogRunner::FileChooserParams& params,
CefFileDialogRunner::RunFileChooserCallback callback);
[[nodiscard]] RunFileChooserCallback MaybeRunDelegate(
const blink::mojom::FileChooserParams& params,
RunFileChooserCallback callback);
// Used with the RunFileChooser variant where the caller specifies a callback
// (no associated RenderFrameHost).
void OnRunFileChooserCallback(
CefFileDialogRunner::RunFileChooserCallback callback,
int selected_accept_filter,
const std::vector<base::FilePath>& file_paths);
void SelectFileDoneByDelegateCallback(
ui::SelectFileDialog::Listener* listener,
void* params,
const std::vector<base::FilePath>& paths);
void SelectFileDoneByListenerCallback(bool listener_destroyed);
// Used with WebContentsDelegate::RunFileChooser when mode is
// blink::mojom::FileChooserParams::Mode::kUploadFolder.
void OnRunFileChooserUploadFolderDelegateCallback(
const blink::mojom::FileChooserParams::Mode mode,
scoped_refptr<content::FileSelectListener> listener,
int selected_accept_filter,
const std::vector<base::FilePath>& file_paths);
// CefBrowserHostBase pointer is guaranteed to outlive this object.
CefBrowserHostBase* const browser_;
// Used with WebContentsDelegate::RunFileChooser to notify the
// RenderFrameHost.
void OnRunFileChooserDelegateCallback(
blink::mojom::FileChooserParams::Mode mode,
scoped_refptr<content::FileSelectListener> listener,
int selected_accept_filter,
const std::vector<base::FilePath>& file_paths);
// Used when running a platform dialog via RunSelectFile.
scoped_refptr<ui::SelectFileDialog> dialog_;
CefSelectFileDialogListener* dialog_listener_ = nullptr;
// Clean up state associated with the last run.
void Cleanup();
// List of all currently active listeners.
std::set<ui::SelectFileDialog::Listener*> active_listeners_;
// AlloyBrowserHostImpl pointer is guaranteed to outlive this object.
AlloyBrowserHostImpl* browser_;
std::unique_ptr<CefFileDialogRunner> runner_;
// True if a file chooser is currently pending.
bool file_chooser_pending_;
// Used for asynchronously listing directory contents.
std::unique_ptr<net::DirectoryLister> lister_;
// Must be the last member.
base::WeakPtrFactory<CefFileDialogManager> weak_ptr_factory_;
base::WeakPtrFactory<CefFileDialogManager> weak_ptr_factory_{this};
};
#endif // CEF_LIBCEF_BROWSER_JAVASCRIPT_DIALOG_MANAGER_H_

View File

@ -0,0 +1,189 @@
// Copyright (c) 2022 The Chromium Embedded Framework Authors.
// Portions copyright (c) 2012 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 "libcef/browser/file_dialog_runner.h"
#include "libcef/browser/browser_host_base.h"
#include "libcef/browser/browser_info_manager.h"
#include "libcef/browser/extensions/browser_extensions_util.h"
#include "base/memory/singleton.h"
#include "chrome/browser/file_select_helper.h"
#include "chrome/browser/ui/chrome_select_file_policy.h"
#include "ui/shell_dialogs/select_file_dialog_factory.h"
#include "ui/shell_dialogs/select_file_policy.h"
using blink::mojom::FileChooserParams;
namespace {
// Creation of a file dialog can be triggered via various code paths, but they
// all eventually result in a call to ui::SelectFileDialog::Create. We intercept
// that call with CefSelectFileDialogFactory and redirect it to
// CefFileDialogManager::RunSelectFile. After triggering the CefDialogHandler
// callbacks that method calls ui::SelectFileDialog::Create again with
// |run_from_cef=false| to trigger creation of the default platform dialog.
class CefSelectFileDialogFactory final : public ui::SelectFileDialogFactory {
public:
CefSelectFileDialogFactory(const CefSelectFileDialogFactory&) = delete;
CefSelectFileDialogFactory& operator=(const CefSelectFileDialogFactory&) =
delete;
static CefSelectFileDialogFactory* GetInstance() {
// Leaky because there is no useful cleanup to do.
return base::Singleton<
CefSelectFileDialogFactory,
base::LeakySingletonTraits<CefSelectFileDialogFactory>>::get();
}
ui::SelectFileDialog* Create(
ui::SelectFileDialog::Listener* listener,
std::unique_ptr<ui::SelectFilePolicy> policy) override;
bool IsCefFactory() const override { return true; }
private:
friend struct base::DefaultSingletonTraits<CefSelectFileDialogFactory>;
CefSelectFileDialogFactory() { ui::SelectFileDialog::SetFactory(this); }
};
CefRefPtr<CefBrowserHostBase> GetBrowserForTopLevelNativeWindow(
gfx::NativeWindow owning_window) {
DCHECK(owning_window);
for (const auto& browser_info :
CefBrowserInfoManager::GetInstance()->GetBrowserInfoList()) {
if (auto browser = browser_info->browser()) {
if (browser->GetTopLevelNativeWindow() == owning_window)
return browser;
}
}
return nullptr;
}
CefRefPtr<CefBrowserHostBase> GetLikelyFocusedBrowser() {
for (const auto& browser_info :
CefBrowserInfoManager::GetInstance()->GetBrowserInfoList()) {
if (auto browser = browser_info->browser()) {
if (browser->IsFocused())
return browser;
}
}
return nullptr;
}
// Delegates the running of the dialog to CefFileDialogManager.
class CefSelectFileDialog final : public ui::SelectFileDialog {
public:
CefSelectFileDialog(ui::SelectFileDialog::Listener* listener,
std::unique_ptr<ui::SelectFilePolicy> policy)
: ui::SelectFileDialog(listener, std::move(policy)) {
DCHECK(listener_);
}
CefSelectFileDialog(const CefSelectFileDialog&) = delete;
CefSelectFileDialog& operator=(const CefSelectFileDialog&) = delete;
void SelectFileImpl(Type type,
const std::u16string& title,
const base::FilePath& default_path,
const FileTypeInfo* file_types,
int file_type_index,
const base::FilePath::StringType& default_extension,
gfx::NativeWindow owning_window,
void* params) override {
// Try to determine the associated browser (with decreasing levels of
// confidence).
// 1. Browser associated with the SelectFilePolicy. This is the most
// reliable mechanism if specified at the SelectFileDialog::Create call
// site.
if (select_file_policy_) {
auto chrome_policy =
static_cast<ChromeSelectFilePolicy*>(select_file_policy_.get());
auto web_contents = chrome_policy->source_contents();
if (web_contents) {
browser_ = extensions::GetOwnerBrowserForHost(
web_contents->GetRenderViewHost(), nullptr);
}
if (!browser_) {
LOG(WARNING) << "No browser associated with SelectFilePolicy";
}
}
// 2. Browser associated with the top-level native window (owning_window).
// This should be reliable with windowed browsers. However, |owning_window|
// will always be nullptr with windowless browsers.
if (!browser_ && owning_window) {
browser_ = GetBrowserForTopLevelNativeWindow(owning_window);
if (!browser_) {
LOG(WARNING) << "No browser associated with top-level native window";
}
}
// 3. Browser most likely to be focused. This may be somewhat iffy with
// windowless browsers as there is no guarantee that the client has only
// one browser focused at a time.
if (!browser_) {
browser_ = GetLikelyFocusedBrowser();
if (!browser_) {
LOG(WARNING) << "No likely focused browser";
}
}
if (!browser_) {
LOG(ERROR)
<< "Failed to identify associated browser; canceling the file dialog";
listener_->FileSelectionCanceled(params);
return;
}
owning_window_ = owning_window;
has_multiple_file_choices_ =
file_types ? file_types->extensions.size() > 1 : true;
browser_->RunSelectFile(listener_, std::move(select_file_policy_), type,
title, default_path, file_types, file_type_index,
default_extension, owning_window, params);
}
bool IsRunning(gfx::NativeWindow owning_window) const override {
return owning_window == owning_window_;
}
void ListenerDestroyed() override {
if (browser_)
browser_->SelectFileListenerDestroyed(listener_);
listener_ = nullptr;
}
bool HasMultipleFileTypeChoicesImpl() override {
return has_multiple_file_choices_;
}
private:
gfx::NativeWindow owning_window_ = nullptr;
bool has_multiple_file_choices_ = false;
CefRefPtr<CefBrowserHostBase> browser_;
};
ui::SelectFileDialog* CefSelectFileDialogFactory::Create(
ui::SelectFileDialog::Listener* listener,
std::unique_ptr<ui::SelectFilePolicy> policy) {
return new CefSelectFileDialog(listener, std::move(policy));
}
} // namespace
namespace file_dialog_runner {
void RegisterFactory() {
// Implicitly registers on creation.
CefSelectFileDialogFactory::GetInstance();
}
} // namespace file_dialog_runner

View File

@ -1,4 +1,4 @@
// Copyright (c) 2012 The Chromium Embedded Framework Authors.
// Copyright (c) 2022 The Chromium Embedded Framework Authors.
// Portions copyright (c) 2012 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.
@ -7,46 +7,11 @@
#define CEF_LIBCEF_BROWSER_FILE_DIALOG_RUNNER_H_
#pragma once
#include <vector>
namespace file_dialog_runner {
#include "base/callback.h"
#include "base/files/file_path.h"
#include "third_party/blink/public/mojom/choosers/file_chooser.mojom.h"
// One-time registration on startup.
void RegisterFactory();
class AlloyBrowserHostImpl;
class CefFileDialogRunner {
public:
CefFileDialogRunner(const CefFileDialogRunner&) = delete;
CefFileDialogRunner& operator=(const CefFileDialogRunner&) = delete;
// Extend blink::mojom::FileChooserParams with some options unique to CEF.
struct FileChooserParams : public blink::mojom::FileChooserParams {
// 0-based index of the selected value in |accept_types|.
int selected_accept_filter = 0;
// True if the Save dialog should prompt before overwriting files.
bool overwriteprompt = true;
// True if read-only files should be hidden.
bool hidereadonly = true;
};
// The argument vector will be empty if the dialog was canceled.
using RunFileChooserCallback =
base::OnceCallback<void(int, const std::vector<base::FilePath>&)>;
// Display the file chooser dialog. Execute |callback| on completion.
virtual void Run(AlloyBrowserHostImpl* browser,
const FileChooserParams& params,
RunFileChooserCallback callback) = 0;
protected:
// Allow deletion via std::unique_ptr only.
friend std::default_delete<CefFileDialogRunner>;
CefFileDialogRunner() = default;
virtual ~CefFileDialogRunner() = default;
};
} // namespace file_dialog_runner
#endif // CEF_LIBCEF_BROWSER_FILE_DIALOG_RUNNER_H_

View File

@ -40,7 +40,6 @@ class CefBrowserPlatformDelegateNativeMac
const content::NativeWebKeyboardEvent& event) override;
CefEventHandle GetEventHandle(
const content::NativeWebKeyboardEvent& event) const override;
std::unique_ptr<CefFileDialogRunner> CreateFileDialogRunner() override;
std::unique_ptr<CefJavaScriptDialogRunner> CreateJavaScriptDialogRunner()
override;
std::unique_ptr<CefMenuRunner> CreateMenuRunner() override;

View File

@ -9,7 +9,6 @@
#include "libcef/browser/alloy/alloy_browser_host_impl.h"
#include "libcef/browser/context.h"
#include "libcef/browser/native/file_dialog_runner_mac.h"
#include "libcef/browser/native/javascript_dialog_runner_mac.h"
#include "libcef/browser/native/menu_runner_mac.h"
#include "libcef/browser/thread_util.h"
@ -363,11 +362,6 @@ CefEventHandle CefBrowserPlatformDelegateNativeMac::GetEventHandle(
return event.os_event;
}
std::unique_ptr<CefFileDialogRunner>
CefBrowserPlatformDelegateNativeMac::CreateFileDialogRunner() {
return base::WrapUnique(new CefFileDialogRunnerMac);
}
std::unique_ptr<CefJavaScriptDialogRunner>
CefBrowserPlatformDelegateNativeMac::CreateJavaScriptDialogRunner() {
return base::WrapUnique(new CefJavaScriptDialogRunnerMac);

View File

@ -10,7 +10,6 @@
#include "libcef/browser/alloy/alloy_browser_host_impl.h"
#include "libcef/browser/context.h"
#include "libcef/browser/native/file_dialog_runner_win.h"
#include "libcef/browser/native/javascript_dialog_runner_win.h"
#include "libcef/browser/native/menu_runner_win.h"
#include "libcef/browser/native/window_delegate_view.h"
@ -447,11 +446,6 @@ CefEventHandle CefBrowserPlatformDelegateNativeWin::GetEventHandle(
const_cast<CHROME_MSG*>(&event.os_event->native_event()));
}
std::unique_ptr<CefFileDialogRunner>
CefBrowserPlatformDelegateNativeWin::CreateFileDialogRunner() {
return base::WrapUnique(new CefFileDialogRunnerWin);
}
std::unique_ptr<CefJavaScriptDialogRunner>
CefBrowserPlatformDelegateNativeWin::CreateJavaScriptDialogRunner() {
return base::WrapUnique(new CefJavaScriptDialogRunnerWin);

View File

@ -34,7 +34,6 @@ class CefBrowserPlatformDelegateNativeWin
const content::NativeWebKeyboardEvent& event) override;
CefEventHandle GetEventHandle(
const content::NativeWebKeyboardEvent& event) const override;
std::unique_ptr<CefFileDialogRunner> CreateFileDialogRunner() override;
std::unique_ptr<CefJavaScriptDialogRunner> CreateJavaScriptDialogRunner()
override;
std::unique_ptr<CefMenuRunner> CreateMenuRunner() override;

View File

@ -1,41 +0,0 @@
// Copyright (c) 2012 The Chromium Embedded Framework Authors.
// Portions copyright (c) 2012 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.
#ifndef CEF_LIBCEF_BROWSER_NATIVE_FILE_DIALOG_RUNNER_MAC_H_
#define CEF_LIBCEF_BROWSER_NATIVE_FILE_DIALOG_RUNNER_MAC_H_
#pragma once
#include "libcef/browser/file_dialog_runner.h"
#include "base/memory/weak_ptr.h"
@class NSView;
class CefFileDialogRunnerMac : public CefFileDialogRunner {
public:
CefFileDialogRunnerMac();
// CefFileDialogRunner methods:
void Run(AlloyBrowserHostImpl* browser,
const FileChooserParams& params,
RunFileChooserCallback callback) override;
private:
static void RunOpenFileDialog(
base::WeakPtr<CefFileDialogRunnerMac> weak_this,
const CefFileDialogRunner::FileChooserParams& params,
NSView* view,
int filter_index);
static void RunSaveFileDialog(
base::WeakPtr<CefFileDialogRunnerMac> weak_this,
const CefFileDialogRunner::FileChooserParams& params,
NSView* view,
int filter_index);
CefFileDialogRunner::RunFileChooserCallback callback_;
base::WeakPtrFactory<CefFileDialogRunnerMac> weak_ptr_factory_;
};
#endif // CEF_LIBCEF_BROWSER_NATIVE_FILE_DIALOG_RUNNER_MAC_H_

View File

@ -1,405 +0,0 @@
// Copyright (c) 2012 The Chromium Embedded Framework Authors.
// Portions copyright (c) 2012 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 "libcef/browser/native/file_dialog_runner_mac.h"
#import <Cocoa/Cocoa.h>
#import <CoreServices/CoreServices.h>
#include "libcef/browser/alloy/alloy_browser_host_impl.h"
#include "base/mac/mac_util.h"
#include "base/stl_util.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_restrictions.h"
#include "cef/grit/cef_strings.h"
#include "chrome/grit/generated_resources.h"
#include "net/base/mime_util.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/strings/grit/ui_strings.h"
namespace {
std::u16string GetDescriptionFromMimeType(const std::string& mime_type) {
// Check for wild card mime types and return an appropriate description.
static const struct {
const char* mime_type;
int string_id;
} kWildCardMimeTypes[] = {
{"audio", IDS_AUDIO_FILES},
{"image", IDS_IMAGE_FILES},
{"text", IDS_TEXT_FILES},
{"video", IDS_VIDEO_FILES},
};
for (size_t i = 0; i < std::size(kWildCardMimeTypes); ++i) {
if (mime_type == std::string(kWildCardMimeTypes[i].mime_type) + "/*")
return l10n_util::GetStringUTF16(kWildCardMimeTypes[i].string_id);
}
return std::u16string();
}
void AddFilters(NSPopUpButton* button,
const std::vector<std::u16string>& accept_filters,
bool include_all_files,
std::vector<std::vector<std::u16string>>* all_extensions) {
for (size_t i = 0; i < accept_filters.size(); ++i) {
const std::u16string& filter = accept_filters[i];
if (filter.empty())
continue;
std::vector<std::u16string> extensions;
std::u16string description;
size_t sep_index = filter.find('|');
if (sep_index != std::string::npos) {
// Treat as a filter of the form "Filter Name|.ext1;.ext2;.ext3".
description = filter.substr(0, sep_index);
const std::vector<std::u16string>& ext =
base::SplitString(filter.substr(sep_index + 1), u";",
base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
for (size_t x = 0; x < ext.size(); ++x) {
const std::u16string& file_ext = ext[x];
if (!file_ext.empty() && file_ext[0] == '.')
extensions.push_back(file_ext);
}
} else if (filter[0] == '.') {
// Treat as an extension beginning with the '.' character.
extensions.push_back(filter);
} else {
// Otherwise convert mime type to one or more extensions.
const std::string& ascii = base::UTF16ToASCII(filter);
std::vector<base::FilePath::StringType> ext;
net::GetExtensionsForMimeType(ascii, &ext);
if (!ext.empty()) {
for (size_t x = 0; x < ext.size(); ++x)
extensions.push_back(u"." + base::ASCIIToUTF16(ext[x]));
description = GetDescriptionFromMimeType(ascii);
}
}
if (extensions.empty())
continue;
// Don't display a crazy number of extensions since the NSPopUpButton width
// will keep growing.
const size_t kMaxExtensions = 10;
std::u16string ext_str;
for (size_t x = 0; x < std::min(kMaxExtensions, extensions.size()); ++x) {
const std::u16string& pattern = u"*" + extensions[x];
if (x != 0)
ext_str += u";";
ext_str += pattern;
}
if (extensions.size() > kMaxExtensions)
ext_str += u";...";
if (description.empty()) {
description = ext_str;
} else {
description += u" (" + ext_str + u")";
}
[button addItemWithTitle:base::SysUTF16ToNSString(description)];
all_extensions->push_back(extensions);
}
// Add the *.* filter, but only if we have added other filters (otherwise it
// is implied).
if (include_all_files && !all_extensions->empty()) {
[button addItemWithTitle:base::SysUTF8ToNSString("All Files (*)")];
all_extensions->push_back(std::vector<std::u16string>());
}
}
} // namespace
// Used to manage the file type filter in the NSSavePanel/NSOpenPanel.
@interface CefFilterDelegate : NSObject {
@private
NSSavePanel* panel_;
std::vector<std::vector<std::u16string>> extensions_;
int selected_index_;
}
- (id)initWithPanel:(NSSavePanel*)panel
andAcceptFilters:(const std::vector<std::u16string>&)accept_filters
andFilterIndex:(int)index;
- (void)setFilter:(int)index;
- (int)filter;
- (void)filterSelectionChanged:(id)sender;
- (void)setFileExtension;
@end
@implementation CefFilterDelegate
- (id)initWithPanel:(NSSavePanel*)panel
andAcceptFilters:(const std::vector<std::u16string>&)accept_filters
andFilterIndex:(int)index {
if (self = [super init]) {
DCHECK(panel);
panel_ = panel;
selected_index_ = 0;
NSPopUpButton* button = [[NSPopUpButton alloc] init];
AddFilters(button, accept_filters, true, &extensions_);
[button sizeToFit];
[button setTarget:self];
[button setAction:@selector(filterSelectionChanged:)];
if (index < static_cast<int>(extensions_.size())) {
[button selectItemAtIndex:index];
[self setFilter:index];
}
[panel_ setAccessoryView:button];
}
return self;
}
// Set the current filter index.
- (void)setFilter:(int)index {
DCHECK(index >= 0 && index < static_cast<int>(extensions_.size()));
selected_index_ = index;
// Set the selectable file types. For open panels this limits the files that
// can be selected. For save panels this applies a default file extenion when
// the dialog is dismissed if none is already provided.
NSMutableArray* acceptArray = nil;
if (!extensions_[index].empty()) {
acceptArray = [[NSMutableArray alloc] init];
for (size_t i = 0; i < extensions_[index].size(); ++i) {
[acceptArray
addObject:base::SysUTF16ToNSString(extensions_[index][i].substr(1))];
}
}
[panel_ setAllowedFileTypes:acceptArray];
if (![panel_ isKindOfClass:[NSOpenPanel class]]) {
// For save panels set the file extension.
[self setFileExtension];
}
}
// Returns the current filter index.
- (int)filter {
return selected_index_;
}
// Called when the selected filter is changed via the NSPopUpButton.
- (void)filterSelectionChanged:(id)sender {
NSPopUpButton* button = (NSPopUpButton*)sender;
[self setFilter:[button indexOfSelectedItem]];
}
// Set the extension on the currently selected file name.
- (void)setFileExtension {
const std::vector<std::u16string>& filter = extensions_[selected_index_];
if (filter.empty()) {
// All extensions are allowed so don't change anything.
return;
}
base::FilePath path(base::SysNSStringToUTF8([panel_ nameFieldStringValue]));
// If the file name currently includes an extension from |filter| then don't
// change anything.
std::u16string extension = base::UTF8ToUTF16(path.Extension());
if (!extension.empty()) {
for (size_t i = 0; i < filter.size(); ++i) {
if (filter[i] == extension)
return;
}
}
// Change the extension to the first value in |filter|.
path = path.ReplaceExtension(base::UTF16ToUTF8(filter[0]));
[panel_ setNameFieldStringValue:base::SysUTF8ToNSString(path.value())];
}
@end
CefFileDialogRunnerMac::CefFileDialogRunnerMac() : weak_ptr_factory_(this) {}
void CefFileDialogRunnerMac::Run(AlloyBrowserHostImpl* browser,
const FileChooserParams& params,
RunFileChooserCallback callback) {
callback_ = std::move(callback);
int filter_index = params.selected_accept_filter;
NSView* owner = CAST_CEF_WINDOW_HANDLE_TO_NSVIEW(browser->GetWindowHandle());
auto weak_this = weak_ptr_factory_.GetWeakPtr();
if (params.mode == blink::mojom::FileChooserParams::Mode::kOpen ||
params.mode == blink::mojom::FileChooserParams::Mode::kOpenMultiple ||
params.mode == blink::mojom::FileChooserParams::Mode::kUploadFolder) {
RunOpenFileDialog(weak_this, params, owner, filter_index);
} else if (params.mode == blink::mojom::FileChooserParams::Mode::kSave) {
RunSaveFileDialog(weak_this, params, owner, filter_index);
} else {
NOTIMPLEMENTED();
}
}
// static
void CefFileDialogRunnerMac::RunOpenFileDialog(
base::WeakPtr<CefFileDialogRunnerMac> weak_this,
const CefFileDialogRunner::FileChooserParams& params,
NSView* view,
int filter_index) {
NSOpenPanel* openPanel = [NSOpenPanel openPanel];
std::u16string title;
if (!params.title.empty()) {
title = params.title;
} else {
title = l10n_util::GetStringUTF16(
params.mode == blink::mojom::FileChooserParams::Mode::kOpen
? IDS_OPEN_FILE_DIALOG_TITLE
: (params.mode ==
blink::mojom::FileChooserParams::Mode::kOpenMultiple
? IDS_OPEN_FILES_DIALOG_TITLE
: IDS_SELECT_FOLDER_DIALOG_TITLE));
}
[openPanel setTitle:base::SysUTF16ToNSString(title)];
std::string filename, directory;
if (!params.default_file_name.empty()) {
if (params.mode == blink::mojom::FileChooserParams::Mode::kUploadFolder ||
params.default_file_name.EndsWithSeparator()) {
// The value is only a directory.
directory = params.default_file_name.value();
} else {
// The value is a file name and possibly a directory.
filename = params.default_file_name.BaseName().value();
directory = params.default_file_name.DirName().value();
}
}
if (!filename.empty()) {
[openPanel setNameFieldStringValue:base::SysUTF8ToNSString(filename)];
}
if (!directory.empty()) {
[openPanel setDirectoryURL:[NSURL fileURLWithPath:base::SysUTF8ToNSString(
directory)]];
}
CefFilterDelegate* filter_delegate = nil;
if (params.mode != blink::mojom::FileChooserParams::Mode::kUploadFolder &&
!params.accept_types.empty()) {
// Add the file filter control.
filter_delegate =
[[CefFilterDelegate alloc] initWithPanel:openPanel
andAcceptFilters:params.accept_types
andFilterIndex:filter_index];
}
// Further panel configuration.
[openPanel setAllowsOtherFileTypes:YES];
[openPanel setAllowsMultipleSelection:
(params.mode ==
blink::mojom::FileChooserParams::Mode::kOpenMultiple)];
[openPanel
setCanChooseFiles:(params.mode !=
blink::mojom::FileChooserParams::Mode::kUploadFolder)];
[openPanel
setCanChooseDirectories:(params.mode == blink::mojom::FileChooserParams::
Mode::kUploadFolder)];
[openPanel setShowsHiddenFiles:!params.hidereadonly];
// Show panel.
[openPanel
beginSheetModalForWindow:[view window]
completionHandler:^(NSInteger returnCode) {
int filter_index_to_use = (filter_delegate != nil)
? [filter_delegate filter]
: filter_index;
if (returnCode == NSFileHandlingPanelOKButton) {
std::vector<base::FilePath> files;
files.reserve(openPanel.URLs.count);
for (NSURL* url in openPanel.URLs) {
if (url.isFileURL)
files.push_back(base::FilePath(url.path.UTF8String));
}
std::move(weak_this->callback_)
.Run(filter_index_to_use, files);
} else {
std::move(weak_this->callback_)
.Run(filter_index_to_use, std::vector<base::FilePath>());
}
}];
}
// static
void CefFileDialogRunnerMac::RunSaveFileDialog(
base::WeakPtr<CefFileDialogRunnerMac> weak_this,
const CefFileDialogRunner::FileChooserParams& params,
NSView* view,
int filter_index) {
NSSavePanel* savePanel = [NSSavePanel savePanel];
std::u16string title;
if (!params.title.empty())
title = params.title;
else
title = l10n_util::GetStringUTF16(IDS_SAVE_AS_DIALOG_TITLE);
[savePanel setTitle:base::SysUTF16ToNSString(title)];
std::string filename, directory;
if (!params.default_file_name.empty()) {
if (params.default_file_name.EndsWithSeparator()) {
// The value is only a directory.
directory = params.default_file_name.value();
} else {
// The value is a file name and possibly a directory.
filename = params.default_file_name.BaseName().value();
directory = params.default_file_name.DirName().value();
}
}
if (!filename.empty()) {
[savePanel setNameFieldStringValue:base::SysUTF8ToNSString(filename)];
}
if (!directory.empty()) {
[savePanel setDirectoryURL:[NSURL fileURLWithPath:base::SysUTF8ToNSString(
directory)]];
}
CefFilterDelegate* filter_delegate = nil;
if (!params.accept_types.empty()) {
// Add the file filter control.
filter_delegate =
[[CefFilterDelegate alloc] initWithPanel:savePanel
andAcceptFilters:params.accept_types
andFilterIndex:filter_index];
}
[savePanel setAllowsOtherFileTypes:YES];
[savePanel setShowsHiddenFiles:!params.hidereadonly];
// Show panel.
[savePanel
beginSheetModalForWindow:view.window
completionHandler:^(NSInteger resultCode) {
int filter_index_to_use = (filter_delegate != nil)
? [filter_delegate filter]
: filter_index;
if (resultCode == NSFileHandlingPanelOKButton) {
NSURL* url = savePanel.URL;
const char* path = url.path.UTF8String;
std::vector<base::FilePath> files(1, base::FilePath(path));
std::move(weak_this->callback_)
.Run(filter_index_to_use, files);
} else {
std::move(weak_this->callback_)
.Run(filter_index_to_use, std::vector<base::FilePath>());
}
}];
}

View File

@ -1,560 +0,0 @@
// Copyright (c) 2012 The Chromium Embedded Framework Authors.
// Portions copyright (c) 2012 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 "libcef/browser/native/file_dialog_runner_win.h"
#include <windows.h>
#include <commdlg.h>
#include <shlobj.h>
#include <wrl/client.h>
#include "libcef/browser/alloy/alloy_browser_host_impl.h"
#include "base/files/file_util.h"
#include "base/stl_util.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/win/registry.h"
#include "cef/grit/cef_strings.h"
#include "chrome/grit/generated_resources.h"
#include "net/base/mime_util.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/win/shell.h"
#include "ui/strings/grit/ui_strings.h"
namespace {
// From ui/base/dialogs/select_file_dialog_win.cc.
// Get the file type description from the registry. This will be "Text Document"
// for .txt files, "JPEG Image" for .jpg files, etc. If the registry doesn't
// have an entry for the file type, we return false, true if the description was
// found. 'file_ext' must be in form ".txt".
static bool GetRegistryDescriptionFromExtension(const std::wstring& file_ext,
std::wstring* reg_description) {
DCHECK(reg_description);
base::win::RegKey reg_ext(HKEY_CLASSES_ROOT, file_ext.c_str(), KEY_READ);
std::wstring reg_app;
if (reg_ext.ReadValue(NULL, &reg_app) == ERROR_SUCCESS && !reg_app.empty()) {
base::win::RegKey reg_link(HKEY_CLASSES_ROOT, reg_app.c_str(), KEY_READ);
if (reg_link.ReadValue(NULL, reg_description) == ERROR_SUCCESS)
return true;
}
return false;
}
// Set up a filter for a Save/Open dialog, which will consist of |file_ext| file
// extensions (internally separated by semicolons), |ext_desc| as the text
// descriptions of the |file_ext| types (optional), and (optionally) the default
// 'All Files' view. The purpose of the filter is to show only files of a
// particular type in a Windows Save/Open dialog box. The resulting filter is
// returned. The filters created here are:
// 1. only files that have 'file_ext' as their extension
// 2. all files (only added if 'include_all_files' is true)
// Example:
// file_ext: { "*.txt", "*.htm;*.html" }
// ext_desc: { "Text Document" }
// returned: "Text Document\0*.txt\0HTML Document\0*.htm;*.html\0"
// "All Files\0*.*\0\0" (in one big string)
// If a description is not provided for a file extension, it will be retrieved
// from the registry. If the file extension does not exist in the registry, it
// will be omitted from the filter, as it is likely a bogus extension.
std::wstring FormatFilterForExtensions(
const std::vector<std::wstring>& file_ext,
const std::vector<std::wstring>& ext_desc,
bool include_all_files) {
const std::wstring all_ext = L"*.*";
const std::wstring all_desc =
base::UTF16ToWide(l10n_util::GetStringUTF16(IDS_APP_SAVEAS_ALL_FILES)) +
L" (" + all_ext + L")";
DCHECK(file_ext.size() >= ext_desc.size());
if (file_ext.empty())
include_all_files = true;
std::wstring result;
// Create all supported .ext filter if more than one filter.
if (file_ext.size() > 1) {
std::set<base::WStringPiece> unique_exts;
for (const auto& exts : file_ext) {
for (const auto& ext : base::SplitStringPiece(
exts, L";", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY)) {
unique_exts.insert(ext);
}
}
if (unique_exts.size() > 1) {
std::wstring ext;
auto it = unique_exts.cbegin();
ext = std::wstring(*it);
for (++it; it != unique_exts.cend(); ++it) {
ext += L";" + std::wstring(*it);
}
std::wstring desc =
base::UTF16ToWide(l10n_util::GetStringUTF16(IDS_CUSTOM_FILES)) +
L" (" + ext + L")";
result.append(desc.c_str(), desc.size() + 1); // Append NULL too.
result.append(ext.c_str(), ext.size() + 1);
}
}
for (size_t i = 0; i < file_ext.size(); ++i) {
std::wstring ext = file_ext[i];
std::wstring desc;
if (i < ext_desc.size())
desc = ext_desc[i];
if (ext.empty()) {
// Force something reasonable to appear in the dialog box if there is no
// extension provided.
include_all_files = true;
continue;
}
if (desc.empty()) {
DCHECK(ext.find(L'.') != std::wstring::npos);
std::wstring first_extension = ext.substr(ext.find(L'.'));
size_t first_separator_index = first_extension.find(L';');
if (first_separator_index != std::wstring::npos)
first_extension = first_extension.substr(0, first_separator_index);
// Find the extension name without the preceeding '.' character.
std::wstring ext_name = first_extension;
size_t ext_index = ext_name.find_first_not_of(L'.');
if (ext_index != std::wstring::npos)
ext_name = ext_name.substr(ext_index);
if (!GetRegistryDescriptionFromExtension(first_extension, &desc)) {
// The extension doesn't exist in the registry.
include_all_files = true;
}
}
if (!desc.empty())
desc += L" (" + ext + L")";
else
desc = ext;
result.append(desc.c_str(), desc.size() + 1); // Append NULL too.
result.append(ext.c_str(), ext.size() + 1);
}
if (include_all_files) {
result.append(all_desc.c_str(), all_desc.size() + 1);
result.append(all_ext.c_str(), all_ext.size() + 1);
}
result.append(1, '\0'); // Double NULL required.
return result;
}
std::wstring GetDescriptionFromMimeType(const std::string& mime_type) {
// Check for wild card mime types and return an appropriate description.
static const struct {
const char* mime_type;
int string_id;
} kWildCardMimeTypes[] = {
{"audio", IDS_AUDIO_FILES},
{"image", IDS_IMAGE_FILES},
{"text", IDS_TEXT_FILES},
{"video", IDS_VIDEO_FILES},
};
for (size_t i = 0; i < std::size(kWildCardMimeTypes); ++i) {
if (mime_type == std::string(kWildCardMimeTypes[i].mime_type) + "/*") {
return base::UTF16ToWide(
l10n_util::GetStringUTF16(kWildCardMimeTypes[i].string_id));
}
}
return std::wstring();
}
std::wstring GetFilterString(
const std::vector<std::u16string>& accept_filters) {
std::vector<std::wstring> extensions;
std::vector<std::wstring> descriptions;
for (size_t i = 0; i < accept_filters.size(); ++i) {
const std::wstring& filter = base::UTF16ToWide(accept_filters[i]);
if (filter.empty())
continue;
size_t sep_index = filter.find(L'|');
if (sep_index != std::wstring::npos) {
// Treat as a filter of the form "Filter Name|.ext1;.ext2;.ext3".
const std::wstring& desc = filter.substr(0, sep_index);
const std::vector<std::u16string>& ext = base::SplitString(
base::WideToUTF16(filter.substr(sep_index + 1)), u";",
base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
std::wstring ext_str;
for (size_t x = 0; x < ext.size(); ++x) {
const std::wstring& file_ext = base::UTF16ToWide(ext[x]);
if (!file_ext.empty() && file_ext[0] == L'.') {
if (!ext_str.empty())
ext_str += L";";
ext_str += L"*" + file_ext;
}
}
if (!ext_str.empty()) {
extensions.push_back(ext_str);
descriptions.push_back(desc);
}
} else if (filter[0] == L'.') {
// Treat as an extension beginning with the '.' character.
extensions.push_back(L"*" + filter);
descriptions.push_back(std::wstring());
} else {
// Otherwise convert mime type to one or more extensions.
const std::string& ascii = base::WideToASCII(filter);
std::vector<base::FilePath::StringType> ext;
std::wstring ext_str;
net::GetExtensionsForMimeType(ascii, &ext);
if (!ext.empty()) {
for (size_t x = 0; x < ext.size(); ++x) {
if (x != 0)
ext_str += L";";
ext_str += L"*." + ext[x];
}
extensions.push_back(ext_str);
descriptions.push_back(GetDescriptionFromMimeType(ascii));
}
}
}
return FormatFilterForExtensions(extensions, descriptions, true);
}
// From chrome/browser/views/shell_dialogs_win.cc
bool RunOpenFileDialog(const CefFileDialogRunner::FileChooserParams& params,
HWND owner,
int* filter_index,
base::FilePath* path) {
OPENFILENAME ofn;
// We must do this otherwise the ofn's FlagsEx may be initialized to random
// junk in release builds which can cause the Places Bar not to show up!
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = owner;
wchar_t filename[MAX_PATH] = {0};
ofn.lpstrFile = filename;
ofn.nMaxFile = MAX_PATH;
std::wstring directory;
if (!params.default_file_name.empty()) {
if (params.default_file_name.EndsWithSeparator()) {
// The value is only a directory.
directory = params.default_file_name.value();
} else {
// The value is a file name and possibly a directory.
base::wcslcpy(filename, params.default_file_name.value().c_str(),
std::size(filename));
directory = params.default_file_name.DirName().value();
}
}
if (!directory.empty())
ofn.lpstrInitialDir = directory.c_str();
std::wstring title;
if (!params.title.empty()) {
title = base::UTF16ToWide(params.title);
} else {
title = base::UTF16ToWide(
l10n_util::GetStringUTF16(IDS_OPEN_FILE_DIALOG_TITLE));
}
if (!title.empty())
ofn.lpstrTitle = title.c_str();
// We use OFN_NOCHANGEDIR so that the user can rename or delete the directory
// without having to close Chrome first.
ofn.Flags =
OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR | OFN_EXPLORER | OFN_ENABLESIZING;
if (params.hidereadonly)
ofn.Flags |= OFN_HIDEREADONLY;
const std::wstring& filter = GetFilterString(params.accept_types);
if (!filter.empty()) {
ofn.lpstrFilter = filter.c_str();
// Indices into |lpstrFilter| start at 1.
ofn.nFilterIndex = *filter_index + 1;
}
bool success = !!GetOpenFileName(&ofn);
if (success) {
*filter_index = ofn.nFilterIndex == 0 ? 0 : ofn.nFilterIndex - 1;
*path = base::FilePath(filename);
}
return success;
}
bool RunOpenMultiFileDialog(
const CefFileDialogRunner::FileChooserParams& params,
HWND owner,
int* filter_index,
std::vector<base::FilePath>* paths) {
OPENFILENAME ofn;
// We must do this otherwise the ofn's FlagsEx may be initialized to random
// junk in release builds which can cause the Places Bar not to show up!
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = owner;
std::unique_ptr<wchar_t[]> filename(new wchar_t[UNICODE_STRING_MAX_CHARS]);
filename[0] = 0;
ofn.lpstrFile = filename.get();
ofn.nMaxFile = UNICODE_STRING_MAX_CHARS;
std::wstring directory;
if (!params.default_file_name.empty()) {
if (params.default_file_name.EndsWithSeparator()) {
// The value is only a directory.
directory = params.default_file_name.value();
} else {
// The value is a file name and possibly a directory.
directory = params.default_file_name.DirName().value();
}
}
if (!directory.empty())
ofn.lpstrInitialDir = directory.c_str();
std::wstring title;
if (!params.title.empty()) {
title = base::UTF16ToWide(params.title);
} else {
title = base::UTF16ToWide(
l10n_util::GetStringUTF16(IDS_OPEN_FILES_DIALOG_TITLE));
}
if (!title.empty())
ofn.lpstrTitle = title.c_str();
// We use OFN_NOCHANGEDIR so that the user can rename or delete the directory
// without having to close Chrome first.
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_EXPLORER |
OFN_ALLOWMULTISELECT | OFN_ENABLESIZING;
if (params.hidereadonly)
ofn.Flags |= OFN_HIDEREADONLY;
const std::wstring& filter = GetFilterString(params.accept_types);
if (!filter.empty()) {
ofn.lpstrFilter = filter.c_str();
// Indices into |lpstrFilter| start at 1.
ofn.nFilterIndex = *filter_index + 1;
}
bool success = !!GetOpenFileName(&ofn);
if (success) {
std::vector<base::FilePath> files;
const wchar_t* selection = ofn.lpstrFile;
while (*selection) { // Empty string indicates end of list.
files.push_back(base::FilePath(selection));
// Skip over filename and null-terminator.
selection += files.back().value().length() + 1;
}
if (files.empty()) {
success = false;
} else if (files.size() == 1) {
// When there is one file, it contains the path and filename.
paths->swap(files);
} else {
// Otherwise, the first string is the path, and the remainder are
// filenames.
std::vector<base::FilePath>::iterator path = files.begin();
for (std::vector<base::FilePath>::iterator file = path + 1;
file != files.end(); ++file) {
paths->push_back(path->Append(*file));
}
}
}
if (success)
*filter_index = ofn.nFilterIndex == 0 ? 0 : ofn.nFilterIndex - 1;
return success;
}
// The callback function for when the select folder dialog is opened.
int CALLBACK BrowseCallbackProc(HWND window,
UINT message,
LPARAM parameter,
LPARAM data) {
if (message == BFFM_INITIALIZED) {
// WParam is TRUE since passing a path.
// data lParam member of the BROWSEINFO structure.
SendMessage(window, BFFM_SETSELECTION, TRUE, (LPARAM)data);
}
return 0;
}
bool RunOpenFolderDialog(const CefFileDialogRunner::FileChooserParams& params,
HWND owner,
base::FilePath* path) {
wchar_t dir_buffer[MAX_PATH + 1] = {0};
bool result = false;
BROWSEINFO browse_info = {0};
browse_info.hwndOwner = owner;
browse_info.pszDisplayName = dir_buffer;
browse_info.ulFlags = BIF_USENEWUI | BIF_RETURNONLYFSDIRS;
std::wstring title;
if (!params.title.empty()) {
title = base::UTF16ToWide(params.title);
} else {
title = base::UTF16ToWide(
l10n_util::GetStringUTF16(IDS_SELECT_FOLDER_DIALOG_TITLE));
}
if (!title.empty())
browse_info.lpszTitle = title.c_str();
const std::wstring& file_path = params.default_file_name.value();
if (!file_path.empty()) {
// Highlight the current value.
browse_info.lParam = (LPARAM)file_path.c_str();
browse_info.lpfn = &BrowseCallbackProc;
}
LPITEMIDLIST list = SHBrowseForFolder(&browse_info);
if (list) {
STRRET out_dir_buffer;
ZeroMemory(&out_dir_buffer, sizeof(out_dir_buffer));
out_dir_buffer.uType = STRRET_WSTR;
Microsoft::WRL::ComPtr<IShellFolder> shell_folder;
if (SHGetDesktopFolder(shell_folder.GetAddressOf()) == NOERROR) {
HRESULT hr = shell_folder->GetDisplayNameOf(list, SHGDN_FORPARSING,
&out_dir_buffer);
if (SUCCEEDED(hr) && out_dir_buffer.uType == STRRET_WSTR) {
*path = base::FilePath(out_dir_buffer.pOleStr);
CoTaskMemFree(out_dir_buffer.pOleStr);
result = true;
} else {
// Use old way if we don't get what we want.
wchar_t old_out_dir_buffer[MAX_PATH + 1];
if (SHGetPathFromIDList(list, old_out_dir_buffer)) {
*path = base::FilePath(old_out_dir_buffer);
result = true;
}
}
}
CoTaskMemFree(list);
}
return result;
}
bool RunSaveFileDialog(const CefFileDialogRunner::FileChooserParams& params,
HWND owner,
int* filter_index,
base::FilePath* path) {
OPENFILENAME ofn;
// We must do this otherwise the ofn's FlagsEx may be initialized to random
// junk in release builds which can cause the Places Bar not to show up!
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = owner;
wchar_t filename[MAX_PATH] = {0};
ofn.lpstrFile = filename;
ofn.nMaxFile = MAX_PATH;
std::wstring directory;
if (!params.default_file_name.empty()) {
if (params.default_file_name.EndsWithSeparator()) {
// The value is only a directory.
directory = params.default_file_name.value();
} else {
// The value is a file name and possibly a directory.
base::wcslcpy(filename, params.default_file_name.value().c_str(),
std::size(filename));
directory = params.default_file_name.DirName().value();
}
}
if (!directory.empty())
ofn.lpstrInitialDir = directory.c_str();
std::wstring title;
if (!params.title.empty()) {
title = base::UTF16ToWide(params.title);
} else {
title =
base::UTF16ToWide(l10n_util::GetStringUTF16(IDS_SAVE_AS_DIALOG_TITLE));
}
if (!title.empty())
ofn.lpstrTitle = title.c_str();
// We use OFN_NOCHANGEDIR so that the user can rename or delete the directory
// without having to close Chrome first.
ofn.Flags =
OFN_EXPLORER | OFN_ENABLESIZING | OFN_NOCHANGEDIR | OFN_PATHMUSTEXIST;
if (params.hidereadonly)
ofn.Flags |= OFN_HIDEREADONLY;
if (params.overwriteprompt)
ofn.Flags |= OFN_OVERWRITEPROMPT;
const std::wstring& filter = GetFilterString(params.accept_types);
if (!filter.empty()) {
ofn.lpstrFilter = filter.c_str();
// Indices into |lpstrFilter| start at 1.
ofn.nFilterIndex = *filter_index + 1;
// If a filter is specified and the default file name is changed then append
// a file extension to the new name.
ofn.lpstrDefExt = L"";
}
bool success = !!GetSaveFileName(&ofn);
if (success) {
*filter_index = ofn.nFilterIndex == 0 ? 0 : ofn.nFilterIndex - 1;
*path = base::FilePath(filename);
}
return success;
}
} // namespace
CefFileDialogRunnerWin::CefFileDialogRunnerWin() {}
void CefFileDialogRunnerWin::Run(AlloyBrowserHostImpl* browser,
const FileChooserParams& params,
RunFileChooserCallback callback) {
int filter_index = params.selected_accept_filter;
std::vector<base::FilePath> files;
HWND owner = browser->GetWindowHandle();
if (params.mode == blink::mojom::FileChooserParams::Mode::kOpen) {
base::FilePath file;
if (RunOpenFileDialog(params, owner, &filter_index, &file))
files.push_back(file);
} else if (params.mode ==
blink::mojom::FileChooserParams::Mode::kOpenMultiple) {
RunOpenMultiFileDialog(params, owner, &filter_index, &files);
} else if (params.mode ==
blink::mojom::FileChooserParams::Mode::kUploadFolder) {
base::FilePath file;
if (RunOpenFolderDialog(params, owner, &file))
files.push_back(file);
} else if (params.mode == blink::mojom::FileChooserParams::Mode::kSave) {
base::FilePath file;
if (RunSaveFileDialog(params, owner, &filter_index, &file))
files.push_back(file);
} else {
NOTIMPLEMENTED();
}
std::move(callback).Run(filter_index, files);
}

View File

@ -1,22 +0,0 @@
// Copyright (c) 2012 The Chromium Embedded Framework Authors.
// Portions copyright (c) 2012 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.
#ifndef CEF_LIBCEF_BROWSER_NATIVE_FILE_DIALOG_RUNNER_WIN_H_
#define CEF_LIBCEF_BROWSER_NATIVE_FILE_DIALOG_RUNNER_WIN_H_
#pragma once
#include "libcef/browser/file_dialog_runner.h"
class CefFileDialogRunnerWin : public CefFileDialogRunner {
public:
CefFileDialogRunnerWin();
// CefFileDialogRunner methods:
void Run(AlloyBrowserHostImpl* browser,
const FileChooserParams& params,
RunFileChooserCallback callback) override;
};
#endif // CEF_LIBCEF_BROWSER_NATIVE_FILE_DIALOG_RUNNER_WIN_H_

View File

@ -194,11 +194,6 @@ CefEventHandle CefBrowserPlatformDelegateOsr::GetEventHandle(
return native_delegate_->GetEventHandle(event);
}
std::unique_ptr<CefFileDialogRunner>
CefBrowserPlatformDelegateOsr::CreateFileDialogRunner() {
return native_delegate_->CreateFileDialogRunner();
}
std::unique_ptr<CefJavaScriptDialogRunner>
CefBrowserPlatformDelegateOsr::CreateJavaScriptDialogRunner() {
return native_delegate_->CreateJavaScriptDialogRunner();

View File

@ -49,7 +49,6 @@ class CefBrowserPlatformDelegateOsr
const content::NativeWebKeyboardEvent& event) override;
CefEventHandle GetEventHandle(
const content::NativeWebKeyboardEvent& event) const override;
std::unique_ptr<CefFileDialogRunner> CreateFileDialogRunner() override;
std::unique_ptr<CefJavaScriptDialogRunner> CreateJavaScriptDialogRunner()
override;
std::unique_ptr<CefMenuRunner> CreateMenuRunner() override;

View File

@ -30,6 +30,33 @@ using content::BrowserThread;
using printing::PageRanges;
using printing::PrintSettings;
namespace {
printing::PrintingContextLinux::CreatePrintDialogFunctionPtr
g_default_create_print_dialog_func = nullptr;
printing::PrintingContextLinux::PdfPaperSizeFunctionPtr
g_default_pdf_paper_size_func = nullptr;
CefRefPtr<CefBrowserHostBase> GetBrowserForContext(
printing::PrintingContextLinux* context) {
return extensions::GetOwnerBrowserForGlobalId(
frame_util::MakeGlobalId(context->render_process_id(),
context->render_frame_id()),
nullptr);
}
CefRefPtr<CefPrintHandler> GetPrintHandlerForBrowser(
CefRefPtr<CefBrowserHostBase> browser) {
if (browser) {
if (auto client = browser->GetClient()) {
return client->GetPrintHandler();
}
}
return nullptr;
}
} // namespace
class CefPrintDialogCallbackImpl : public CefPrintDialogCallback {
public:
explicit CefPrintDialogCallbackImpl(CefRefPtr<CefPrintDialogLinux> dialog)
@ -104,7 +131,30 @@ class CefPrintJobCallbackImpl : public CefPrintJobCallback {
printing::PrintDialogGtkInterface* CefPrintDialogLinux::CreatePrintDialog(
PrintingContextLinux* context) {
CEF_REQUIRE_UIT();
return new CefPrintDialogLinux(context);
printing::PrintDialogGtkInterface* interface = nullptr;
auto browser = GetBrowserForContext(context);
if (!browser) {
LOG(ERROR) << "No associated browser in CreatePrintDialog; using default "
"printing implementation.";
}
auto handler = GetPrintHandlerForBrowser(browser);
if (!handler) {
if (g_default_create_print_dialog_func) {
interface = g_default_create_print_dialog_func(context);
DCHECK(interface);
}
} else {
interface = new CefPrintDialogLinux(context, browser, handler);
}
if (!interface) {
LOG(ERROR) << "Null interface in CreatePrintDialog; printing will fail.";
}
return interface;
}
// static
@ -114,27 +164,42 @@ gfx::Size CefPrintDialogLinux::GetPdfPaperSize(
gfx::Size size;
auto browser = extensions::GetOwnerBrowserForGlobalId(
frame_util::MakeGlobalId(context->render_process_id(),
context->render_frame_id()),
nullptr);
DCHECK(browser);
if (browser && browser->GetClient()) {
if (auto handler = browser->GetClient()->GetPrintHandler()) {
const printing::PrintSettings& settings = context->settings();
CefSize cef_size = handler->GetPdfPaperSize(
browser.get(), settings.device_units_per_inch());
size.SetSize(cef_size.width, cef_size.height);
auto browser = GetBrowserForContext(context);
if (!browser) {
LOG(ERROR) << "No associated browser in GetPdfPaperSize; using default "
"printing implementation.";
}
auto handler = GetPrintHandlerForBrowser(browser);
if (!handler) {
if (g_default_pdf_paper_size_func) {
size = g_default_pdf_paper_size_func(context);
DCHECK(!size.IsEmpty());
}
} else {
const printing::PrintSettings& settings = context->settings();
CefSize cef_size = handler->GetPdfPaperSize(
browser.get(), settings.device_units_per_inch());
size.SetSize(cef_size.width, cef_size.height);
}
if (size.IsEmpty()) {
LOG(ERROR) << "Empty size value returned in GetPdfPaperSize; "
"PDF printing will fail.";
LOG(ERROR) << "Empty size value returned in GetPdfPaperSize; PDF printing "
"will fail.";
}
return size;
}
// static
void CefPrintDialogLinux::SetDefaultPrintingContextFuncs(
printing::PrintingContextLinux::CreatePrintDialogFunctionPtr
create_print_dialog_func,
printing::PrintingContextLinux::PdfPaperSizeFunctionPtr
pdf_paper_size_func) {
g_default_create_print_dialog_func = create_print_dialog_func;
g_default_pdf_paper_size_func = pdf_paper_size_func;
}
// static
void CefPrintDialogLinux::OnPrintStart(CefRefPtr<CefBrowserHostBase> browser) {
CEF_REQUIRE_UIT();
@ -146,14 +211,13 @@ void CefPrintDialogLinux::OnPrintStart(CefRefPtr<CefBrowserHostBase> browser) {
}
}
CefPrintDialogLinux::CefPrintDialogLinux(PrintingContextLinux* context)
: context_(context) {
CefPrintDialogLinux::CefPrintDialogLinux(PrintingContextLinux* context,
CefRefPtr<CefBrowserHostBase> browser,
CefRefPtr<CefPrintHandler> handler)
: context_(context), browser_(browser), handler_(handler) {
DCHECK(context_);
browser_ = extensions::GetOwnerBrowserForGlobalId(
frame_util::MakeGlobalId(context_->render_process_id(),
context_->render_frame_id()),
nullptr);
DCHECK(browser_);
DCHECK(handler_);
}
CefPrintDialogLinux::~CefPrintDialogLinux() {
@ -161,7 +225,7 @@ CefPrintDialogLinux::~CefPrintDialogLinux() {
// object because the PrintJobWorker which owns |context_| may already have
// been deleted.
CEF_REQUIRE_UIT();
ReleaseHandler();
handler_->OnPrintReset(browser_.get());
}
void CefPrintDialogLinux::UseDefaultSettings() {
@ -179,12 +243,6 @@ void CefPrintDialogLinux::ShowDialog(
PrintingContextLinux::PrintSettingsCallback callback) {
CEF_REQUIRE_UIT();
SetHandler();
if (!handler_.get()) {
std::move(callback).Run(printing::mojom::ResultCode::kCanceled);
return;
}
callback_ = std::move(callback);
CefRefPtr<CefPrintDialogCallbackImpl> callback_impl(
@ -240,31 +298,11 @@ void CefPrintDialogLinux::ReleaseDialog() {
Release();
}
void CefPrintDialogLinux::SetHandler() {
if (handler_.get())
return;
if (browser_ && browser_->GetClient()) {
handler_ = browser_->GetClient()->GetPrintHandler();
}
}
void CefPrintDialogLinux::ReleaseHandler() {
if (handler_.get()) {
handler_->OnPrintReset(browser_.get());
handler_ = nullptr;
}
}
bool CefPrintDialogLinux::UpdateSettings(
std::unique_ptr<PrintSettings> settings,
bool get_defaults) {
CEF_REQUIRE_UIT();
SetHandler();
if (!handler_.get())
return false;
CefRefPtr<CefPrintSettingsImpl> settings_impl(
new CefPrintSettingsImpl(std::move(settings), false));
handler_->OnPrintSettings(browser_.get(), settings_impl.get(), get_defaults);

View File

@ -39,6 +39,13 @@ class CefPrintDialogLinux : public printing::PrintDialogGtkInterface,
// Returns the paper size in device units.
static gfx::Size GetPdfPaperSize(printing::PrintingContextLinux* context);
// Used for calling into the default GTK implementation.
static void SetDefaultPrintingContextFuncs(
printing::PrintingContextLinux::CreatePrintDialogFunctionPtr
create_print_dialog_func,
printing::PrintingContextLinux::PdfPaperSizeFunctionPtr
pdf_paper_size_func);
// Notify the client when printing has started.
static void OnPrintStart(CefRefPtr<CefBrowserHostBase> browser);
@ -65,12 +72,11 @@ class CefPrintDialogLinux : public printing::PrintDialogGtkInterface,
friend class CefPrintDialogCallbackImpl;
friend class CefPrintJobCallbackImpl;
explicit CefPrintDialogLinux(PrintingContextLinux* context);
CefPrintDialogLinux(PrintingContextLinux* context,
CefRefPtr<CefBrowserHostBase> browser,
CefRefPtr<CefPrintHandler> handler);
~CefPrintDialogLinux() override;
void SetHandler();
void ReleaseHandler();
bool UpdateSettings(std::unique_ptr<printing::PrintSettings> settings,
bool get_defaults);
@ -84,12 +90,12 @@ class CefPrintDialogLinux : public printing::PrintDialogGtkInterface,
// Handles print job response.
void OnJobCompleted();
CefRefPtr<CefPrintHandler> handler_;
// Printing dialog callback.
PrintingContextLinux::PrintSettingsCallback callback_;
PrintingContextLinux* context_;
CefRefPtr<CefBrowserHostBase> browser_;
CefRefPtr<CefPrintHandler> handler_;
base::FilePath path_to_pdf_;
};

View File

@ -257,11 +257,6 @@ CefEventHandle CefBrowserPlatformDelegateViews::GetEventHandle(
return native_delegate_->GetEventHandle(event);
}
std::unique_ptr<CefFileDialogRunner>
CefBrowserPlatformDelegateViews::CreateFileDialogRunner() {
return native_delegate_->CreateFileDialogRunner();
}
std::unique_ptr<CefJavaScriptDialogRunner>
CefBrowserPlatformDelegateViews::CreateJavaScriptDialogRunner() {
return native_delegate_->CreateJavaScriptDialogRunner();

View File

@ -60,7 +60,6 @@ class CefBrowserPlatformDelegateViews
const content::NativeWebKeyboardEvent& event) override;
CefEventHandle GetEventHandle(
const content::NativeWebKeyboardEvent& event) const override;
std::unique_ptr<CefFileDialogRunner> CreateFileDialogRunner() override;
std::unique_ptr<CefJavaScriptDialogRunner> CreateJavaScriptDialogRunner()
override;
std::unique_ptr<CefMenuRunner> CreateMenuRunner() override;

View File

@ -9,7 +9,7 @@
// implementations. See the translator.README.txt file in the tools directory
// for more information.
//
// $hash=289bb032a65bfd1f35a97d93e14df1f5762a9394$
// $hash=65c260e354b6dc85bf121b60081eff450b043542$
//
#include "libcef_dll/cpptoc/browser_host_cpptoc.h"
@ -318,7 +318,6 @@ browser_host_run_file_dialog(struct _cef_browser_host_t* self,
const cef_string_t* title,
const cef_string_t* default_file_path,
cef_string_list_t accept_filters,
int selected_accept_filter,
cef_run_file_dialog_callback_t* callback) {
shutdown_checker::AssertNotShutdown();
@ -327,10 +326,6 @@ browser_host_run_file_dialog(struct _cef_browser_host_t* self,
DCHECK(self);
if (!self)
return;
// Verify param: selected_accept_filter; type: simple_byval
DCHECK_GE(selected_accept_filter, 0);
if (selected_accept_filter < 0)
return;
// Verify param: callback; type: refptr_diff
DCHECK(callback);
if (!callback)
@ -344,7 +339,7 @@ browser_host_run_file_dialog(struct _cef_browser_host_t* self,
// Execute
CefBrowserHostCppToC::Get(self)->RunFileDialog(
mode, CefString(title), CefString(default_file_path), accept_filtersList,
selected_accept_filter, CefRunFileDialogCallbackCToCpp::Wrap(callback));
CefRunFileDialogCallbackCToCpp::Wrap(callback));
}
void CEF_CALLBACK browser_host_start_download(struct _cef_browser_host_t* self,

View File

@ -9,7 +9,7 @@
// implementations. See the translator.README.txt file in the tools directory
// for more information.
//
// $hash=639576c610ca3898809cdee6d19c45253e9ea4d2$
// $hash=3e2fc4cf108e13165c53ee3e8b10b483dbe5ff5e$
//
#include "libcef_dll/cpptoc/dialog_handler_cpptoc.h"
@ -29,7 +29,6 @@ dialog_handler_on_file_dialog(struct _cef_dialog_handler_t* self,
const cef_string_t* title,
const cef_string_t* default_file_path,
cef_string_list_t accept_filters,
int selected_accept_filter,
cef_file_dialog_callback_t* callback) {
shutdown_checker::AssertNotShutdown();
@ -42,10 +41,6 @@ dialog_handler_on_file_dialog(struct _cef_dialog_handler_t* self,
DCHECK(browser);
if (!browser)
return 0;
// Verify param: selected_accept_filter; type: simple_byval
DCHECK_GE(selected_accept_filter, 0);
if (selected_accept_filter < 0)
return 0;
// Verify param: callback; type: refptr_diff
DCHECK(callback);
if (!callback)
@ -59,7 +54,7 @@ dialog_handler_on_file_dialog(struct _cef_dialog_handler_t* self,
// Execute
bool _retval = CefDialogHandlerCppToC::Get(self)->OnFileDialog(
CefBrowserCToCpp::Wrap(browser), mode, CefString(title),
CefString(default_file_path), accept_filtersList, selected_accept_filter,
CefString(default_file_path), accept_filtersList,
CefFileDialogCallbackCToCpp::Wrap(callback));
// Return type: bool

View File

@ -9,7 +9,7 @@
// implementations. See the translator.README.txt file in the tools directory
// for more information.
//
// $hash=d334e579f498ad7727721dfe4e10ad810b81035a$
// $hash=1abedb0e8e7a0101d9ff3f4918f992f3c010d5a6$
//
#include "libcef_dll/cpptoc/file_dialog_callback_cpptoc.h"
@ -22,7 +22,6 @@ namespace {
void CEF_CALLBACK
file_dialog_callback_cont(struct _cef_file_dialog_callback_t* self,
int selected_accept_filter,
cef_string_list_t file_paths) {
shutdown_checker::AssertNotShutdown();
@ -31,10 +30,6 @@ file_dialog_callback_cont(struct _cef_file_dialog_callback_t* self,
DCHECK(self);
if (!self)
return;
// Verify param: selected_accept_filter; type: simple_byval
DCHECK_GE(selected_accept_filter, 0);
if (selected_accept_filter < 0)
return;
// Unverified params: file_paths
// Translate param: file_paths; type: string_vec_byref_const
@ -42,8 +37,7 @@ file_dialog_callback_cont(struct _cef_file_dialog_callback_t* self,
transfer_string_list_contents(file_paths, file_pathsList);
// Execute
CefFileDialogCallbackCppToC::Get(self)->Continue(selected_accept_filter,
file_pathsList);
CefFileDialogCallbackCppToC::Get(self)->Continue(file_pathsList);
}
void CEF_CALLBACK

View File

@ -9,7 +9,7 @@
// implementations. See the translator.README.txt file in the tools directory
// for more information.
//
// $hash=2e6aa9015192a3704df073f7dad0c6fa3b05f76c$
// $hash=15fb714ee545d6ea2057ab82aec380dc25739199$
//
#include "libcef_dll/cpptoc/run_file_dialog_callback_cpptoc.h"
@ -22,7 +22,6 @@ namespace {
void CEF_CALLBACK run_file_dialog_callback_on_file_dialog_dismissed(
struct _cef_run_file_dialog_callback_t* self,
int selected_accept_filter,
cef_string_list_t file_paths) {
shutdown_checker::AssertNotShutdown();
@ -31,10 +30,6 @@ void CEF_CALLBACK run_file_dialog_callback_on_file_dialog_dismissed(
DCHECK(self);
if (!self)
return;
// Verify param: selected_accept_filter; type: simple_byval
DCHECK_GE(selected_accept_filter, 0);
if (selected_accept_filter < 0)
return;
// Unverified params: file_paths
// Translate param: file_paths; type: string_vec_byref_const
@ -43,7 +38,7 @@ void CEF_CALLBACK run_file_dialog_callback_on_file_dialog_dismissed(
// Execute
CefRunFileDialogCallbackCppToC::Get(self)->OnFileDialogDismissed(
selected_accept_filter, file_pathsList);
file_pathsList);
}
} // namespace

View File

@ -9,7 +9,7 @@
// implementations. See the translator.README.txt file in the tools directory
// for more information.
//
// $hash=2edab12ab1759213ab9a6b7620ea39a74291abc7$
// $hash=fa3208182bcdb9aab36096b3ce5ecdd35cb0a80f$
//
#include "libcef_dll/ctocpp/browser_host_ctocpp.h"
@ -261,7 +261,6 @@ void CefBrowserHostCToCpp::RunFileDialog(
const CefString& title,
const CefString& default_file_path,
const std::vector<CefString>& accept_filters,
int selected_accept_filter,
CefRefPtr<CefRunFileDialogCallback> callback) {
shutdown_checker::AssertNotShutdown();
@ -271,10 +270,6 @@ void CefBrowserHostCToCpp::RunFileDialog(
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Verify param: selected_accept_filter; type: simple_byval
DCHECK_GE(selected_accept_filter, 0);
if (selected_accept_filter < 0)
return;
// Verify param: callback; type: refptr_diff
DCHECK(callback.get());
if (!callback.get())
@ -290,7 +285,6 @@ void CefBrowserHostCToCpp::RunFileDialog(
// Execute
_struct->run_file_dialog(_struct, mode, title.GetStruct(),
default_file_path.GetStruct(), accept_filtersList,
selected_accept_filter,
CefRunFileDialogCallbackCppToC::Wrap(callback));
// Restore param:accept_filters; type: string_vec_byref_const

View File

@ -9,7 +9,7 @@
// implementations. See the translator.README.txt file in the tools directory
// for more information.
//
// $hash=6de4205143b6855e7ccf54da14a0494db0b4aaa3$
// $hash=e82e7bf06a027262268172fd74254a8af087e528$
//
#ifndef CEF_LIBCEF_DLL_CTOCPP_BROWSER_HOST_CTOCPP_H_
@ -52,7 +52,6 @@ class CefBrowserHostCToCpp : public CefCToCppRefCounted<CefBrowserHostCToCpp,
const CefString& title,
const CefString& default_file_path,
const std::vector<CefString>& accept_filters,
int selected_accept_filter,
CefRefPtr<CefRunFileDialogCallback> callback) override;
void StartDownload(const CefString& url) override;
void DownloadImage(const CefString& image_url,

View File

@ -9,7 +9,7 @@
// implementations. See the translator.README.txt file in the tools directory
// for more information.
//
// $hash=cac933371fc47c864230d4537ef1da76cd7e4d8e$
// $hash=336c57e3c57a1a5bf8fa4a39aee8f204788ccddb$
//
#include "libcef_dll/ctocpp/dialog_handler_ctocpp.h"
@ -27,7 +27,6 @@ bool CefDialogHandlerCToCpp::OnFileDialog(
const CefString& title,
const CefString& default_file_path,
const std::vector<CefString>& accept_filters,
int selected_accept_filter,
CefRefPtr<CefFileDialogCallback> callback) {
shutdown_checker::AssertNotShutdown();
@ -41,10 +40,6 @@ bool CefDialogHandlerCToCpp::OnFileDialog(
DCHECK(browser.get());
if (!browser.get())
return false;
// Verify param: selected_accept_filter; type: simple_byval
DCHECK_GE(selected_accept_filter, 0);
if (selected_accept_filter < 0)
return false;
// Verify param: callback; type: refptr_diff
DCHECK(callback.get());
if (!callback.get())
@ -60,7 +55,7 @@ bool CefDialogHandlerCToCpp::OnFileDialog(
// Execute
int _retval = _struct->on_file_dialog(
_struct, CefBrowserCppToC::Wrap(browser), mode, title.GetStruct(),
default_file_path.GetStruct(), accept_filtersList, selected_accept_filter,
default_file_path.GetStruct(), accept_filtersList,
CefFileDialogCallbackCppToC::Wrap(callback));
// Restore param:accept_filters; type: string_vec_byref_const

View File

@ -9,7 +9,7 @@
// implementations. See the translator.README.txt file in the tools directory
// for more information.
//
// $hash=4c07a40d3bd171adf3ae3cc4aa935bc7eca4aa5e$
// $hash=1577adae508ad046bb2c7786f040ccc599087b8d$
//
#ifndef CEF_LIBCEF_DLL_CTOCPP_DIALOG_HANDLER_CTOCPP_H_
@ -41,7 +41,6 @@ class CefDialogHandlerCToCpp
const CefString& title,
const CefString& default_file_path,
const std::vector<CefString>& accept_filters,
int selected_accept_filter,
CefRefPtr<CefFileDialogCallback> callback) override;
};

View File

@ -9,7 +9,7 @@
// implementations. See the translator.README.txt file in the tools directory
// for more information.
//
// $hash=8fecb808fb6a84d630d1e8c5380a5ffd900b3654$
// $hash=9fb143d4df823ed6a7dfca295ce4ca2b5756df9c$
//
#include "libcef_dll/ctocpp/file_dialog_callback_ctocpp.h"
@ -20,7 +20,6 @@
NO_SANITIZE("cfi-icall")
void CefFileDialogCallbackCToCpp::Continue(
int selected_accept_filter,
const std::vector<CefString>& file_paths) {
shutdown_checker::AssertNotShutdown();
@ -30,10 +29,6 @@ void CefFileDialogCallbackCToCpp::Continue(
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Verify param: selected_accept_filter; type: simple_byval
DCHECK_GE(selected_accept_filter, 0);
if (selected_accept_filter < 0)
return;
// Unverified params: file_paths
// Translate param: file_paths; type: string_vec_byref_const
@ -43,7 +38,7 @@ void CefFileDialogCallbackCToCpp::Continue(
transfer_string_list_contents(file_paths, file_pathsList);
// Execute
_struct->cont(_struct, selected_accept_filter, file_pathsList);
_struct->cont(_struct, file_pathsList);
// Restore param:file_paths; type: string_vec_byref_const
if (file_pathsList)

View File

@ -9,7 +9,7 @@
// implementations. See the translator.README.txt file in the tools directory
// for more information.
//
// $hash=d84ac439b3372160aa3886b28b3ff81e49f05a6d$
// $hash=acb14970579704b71425d23b2bb7468f782a1e17$
//
#ifndef CEF_LIBCEF_DLL_CTOCPP_FILE_DIALOG_CALLBACK_CTOCPP_H_
@ -36,8 +36,7 @@ class CefFileDialogCallbackCToCpp
virtual ~CefFileDialogCallbackCToCpp();
// CefFileDialogCallback methods.
void Continue(int selected_accept_filter,
const std::vector<CefString>& file_paths) override;
void Continue(const std::vector<CefString>& file_paths) override;
void Cancel() override;
};

View File

@ -9,7 +9,7 @@
// implementations. See the translator.README.txt file in the tools directory
// for more information.
//
// $hash=cb29585261ed25ddd2ee1b4b5c890565e72e5d22$
// $hash=ef632f8846499c0605300240a2ec7240a1750ce2$
//
#include "libcef_dll/ctocpp/run_file_dialog_callback_ctocpp.h"
@ -20,7 +20,6 @@
NO_SANITIZE("cfi-icall")
void CefRunFileDialogCallbackCToCpp::OnFileDialogDismissed(
int selected_accept_filter,
const std::vector<CefString>& file_paths) {
shutdown_checker::AssertNotShutdown();
@ -30,10 +29,6 @@ void CefRunFileDialogCallbackCToCpp::OnFileDialogDismissed(
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Verify param: selected_accept_filter; type: simple_byval
DCHECK_GE(selected_accept_filter, 0);
if (selected_accept_filter < 0)
return;
// Unverified params: file_paths
// Translate param: file_paths; type: string_vec_byref_const
@ -43,8 +38,7 @@ void CefRunFileDialogCallbackCToCpp::OnFileDialogDismissed(
transfer_string_list_contents(file_paths, file_pathsList);
// Execute
_struct->on_file_dialog_dismissed(_struct, selected_accept_filter,
file_pathsList);
_struct->on_file_dialog_dismissed(_struct, file_pathsList);
// Restore param:file_paths; type: string_vec_byref_const
if (file_pathsList)

View File

@ -9,7 +9,7 @@
// implementations. See the translator.README.txt file in the tools directory
// for more information.
//
// $hash=63d2d1da715395296899acc4ed165cf7dae4d78c$
// $hash=12c1546549e1b0d29beb91241361581f3e3da67f$
//
#ifndef CEF_LIBCEF_DLL_CTOCPP_RUN_FILE_DIALOG_CALLBACK_CTOCPP_H_
@ -38,8 +38,7 @@ class CefRunFileDialogCallbackCToCpp
virtual ~CefRunFileDialogCallbackCToCpp();
// CefRunFileDialogCallback methods.
void OnFileDialogDismissed(int selected_accept_filter,
const std::vector<CefString>& file_paths) override;
void OnFileDialogDismissed(const std::vector<CefString>& file_paths) override;
};
#endif // CEF_LIBCEF_DLL_CTOCPP_RUN_FILE_DIALOG_CALLBACK_CTOCPP_H_

View File

@ -202,6 +202,10 @@ patches = [
{
# Changes to support the Chrome runtime in CEF.
# https://bitbucket.org/chromiumembedded/cef/issues/2969
#
# Fix fatal error: 'components/printing/common/print.mojom.h' file not found
# From chrome/browser/ui/browser_commands.cc via
# chrome/browser/printing/print_view_manager_common.h
'name': 'chrome_browser_browser',
},
{
@ -217,6 +221,14 @@ patches = [
# https://bitbucket.org/chromiumembedded/cef/issues/2969
'name': 'chrome_browser_context_menus',
},
{
# Support use of chrome dialogs with CEF runtimes.
# - Adds support for FileSelectHelper and SelectFileDialog interception.
# - Adds additional type filters for dialogs created via FileSelectHelper.
# - Adds support for chaining PrintingContextLinux callbacks.
# https://bitbucket.org/chromiumembedded/cef/issues/3314
'name': 'chrome_browser_dialogs',
},
{
# chrome: Support override of ChromeMimeHandlerViewGuestDelegate.
# https://bitbucket.org/chromiumembedded/cef/issues/2969
@ -243,15 +255,6 @@ patches = [
# https://bitbucket.org/chromiumembedded/cef/issues/2969
'name': 'chrome_browser_profile_menu',
},
{
# Show the CEF Save As dialog.
# https://bitbucket.org/chromiumembedded/cef/issues/2613
#
# Fix fatal error: 'components/printing/common/print.mojom.h' file not found
# From chrome/browser/ui/browser_commands.cc via
# chrome/browser/printing/print_view_manager_common.h
'name': 'chrome_browser_net_export',
},
{
# Support override of the User-Agent product component when NetworkService
# is enabled.

View File

@ -12,6 +12,45 @@ index 9e534ff1683f1..de406f5879be0 100644
return false;
}
diff --git chrome/browser/ui/BUILD.gn chrome/browser/ui/BUILD.gn
index 936021a313995..2dd2554f8a7c5 100644
--- chrome/browser/ui/BUILD.gn
+++ chrome/browser/ui/BUILD.gn
@@ -10,6 +10,7 @@ import("//build/config/features.gni")
import("//build/config/linux/gtk/gtk.gni")
import("//build/config/ozone.gni")
import("//build/config/ui.gni")
+import("//cef/libcef/features/features.gni")
import("//chrome/browser/buildflags.gni")
import("//chrome/common/features.gni")
import("//chromeos/assistant/assistant.gni")
@@ -353,6 +354,10 @@ static_library("ui") {
"//build/config/compiler:wexit_time_destructors",
]
+ if (enable_cef) {
+ configs += [ "//cef/libcef/features:config" ]
+ }
+
# Since browser and browser_ui actually depend on each other,
# we must omit the dependency from browser_ui to browser.
# However, this means browser_ui and browser should more or less
@@ -375,6 +380,7 @@ static_library("ui") {
"//build:branding_buildflags",
"//build:chromeos_buildflags",
"//cc/paint",
+ "//cef/libcef/features",
"//chrome:extra_resources",
"//chrome:resources",
"//chrome:strings",
@@ -5301,6 +5307,7 @@ static_library("ui") {
if (enable_basic_printing) {
deps += [
"//components/printing/browser",
+ "//components/printing/common:mojo_interfaces",
"//printing",
]
}
diff --git chrome/browser/ui/browser.cc chrome/browser/ui/browser.cc
index 3284c6c6353cc..6694f9000c14a 100644
--- chrome/browser/ui/browser.cc

View File

@ -0,0 +1,400 @@
diff --git chrome/browser/file_select_helper.cc chrome/browser/file_select_helper.cc
index 8792cc3a5d40e..8807feaf6063c 100644
--- chrome/browser/file_select_helper.cc
+++ chrome/browser/file_select_helper.cc
@@ -20,6 +20,7 @@
#include "base/threading/hang_watcher.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
+#include "cef/libcef/features/runtime.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/enterprise/connectors/common.h"
#include "chrome/browser/platform_util.h"
@@ -254,6 +255,13 @@ void FileSelectHelper::OnListFile(
void FileSelectHelper::LaunchConfirmationDialog(
const base::FilePath& path,
std::vector<ui::SelectedFileInfo> selected_files) {
+ if (cef::IsAlloyRuntimeEnabled() || run_from_cef_) {
+ // Don't show the upload confirmation dialog with the Alloy runtime, or
+ // when triggered via CEF (initially or recursively).
+ ConvertToFileChooserFileInfoList(selected_files);
+ return;
+ }
+
ShowFolderUploadConfirmationDialog(
path,
base::BindOnce(&FileSelectHelper::ConvertToFileChooserFileInfoList, this),
@@ -450,7 +458,8 @@ void FileSelectHelper::DontAbortOnMissingWebContentsForTesting() {
std::unique_ptr<ui::SelectFileDialog::FileTypeInfo>
FileSelectHelper::GetFileTypesFromAcceptType(
- const std::vector<std::u16string>& accept_types) {
+ const std::vector<std::u16string>& accept_types,
+ bool run_from_cef) {
std::unique_ptr<ui::SelectFileDialog::FileTypeInfo> base_file_type(
new ui::SelectFileDialog::FileTypeInfo());
if (accept_types.empty())
@@ -464,17 +473,24 @@ FileSelectHelper::GetFileTypesFromAcceptType(
std::vector<base::FilePath::StringType>* extensions =
&file_type->extensions.back();
+ // Create individual filters for each accept type.
+ std::vector<std::vector<base::FilePath::StringType>> all_extensions;
+ std::vector<std::u16string> all_overrides;
+
// Find the corresponding extensions.
int valid_type_count = 0;
int description_id = 0;
for (const auto& accept_type : accept_types) {
+ std::vector<base::FilePath::StringType> current_extensions;
+ description_id = 0;
+
size_t old_extension_size = extensions->size();
if (accept_type[0] == '.') {
// If the type starts with a period it is assumed to be a file extension
// so we just have to add it to the list.
base::FilePath::StringType ext =
base::FilePath::FromUTF16Unsafe(accept_type).value();
- extensions->push_back(ext.substr(1));
+ current_extensions.push_back(ext.substr(1));
} else {
if (!base::IsStringASCII(accept_type))
continue;
@@ -485,10 +501,18 @@ FileSelectHelper::GetFileTypesFromAcceptType(
description_id = IDS_AUDIO_FILES;
else if (ascii_type == "video/*")
description_id = IDS_VIDEO_FILES;
-
- net::GetExtensionsForMimeType(ascii_type, extensions);
+ net::GetExtensionsForMimeType(ascii_type, &current_extensions);
}
+ if (!current_extensions.empty()) {
+ all_extensions.push_back(current_extensions);
+ all_overrides.push_back(description_id != 0 ?
+ l10n_util::GetStringUTF16(description_id) :
+ std::u16string());
+
+ extensions->insert(extensions->end(), current_extensions.begin(),
+ current_extensions.end());
+ }
if (extensions->size() > old_extension_size)
valid_type_count++;
}
@@ -513,6 +537,15 @@ FileSelectHelper::GetFileTypesFromAcceptType(
l10n_util::GetStringUTF16(description_id));
}
+ if (run_from_cef && all_extensions.size() > 1) {
+ // Insert filters for the specific accept types at the beginning.
+ file_type->extensions.insert(file_type->extensions.begin(),
+ all_extensions.begin(), all_extensions.end());
+ file_type->extension_description_overrides.insert(
+ file_type->extension_description_overrides.begin(),
+ all_overrides.begin(), all_overrides.end());
+ }
+
return file_type;
}
@@ -520,7 +553,8 @@ FileSelectHelper::GetFileTypesFromAcceptType(
void FileSelectHelper::RunFileChooser(
content::RenderFrameHost* render_frame_host,
scoped_refptr<content::FileSelectListener> listener,
- const FileChooserParams& params) {
+ const FileChooserParams& params,
+ bool run_from_cef) {
Profile* profile = Profile::FromBrowserContext(
render_frame_host->GetProcess()->GetBrowserContext());
@@ -539,6 +573,7 @@ void FileSelectHelper::RunFileChooser(
// message.
scoped_refptr<FileSelectHelper> file_select_helper(
new FileSelectHelper(profile));
+ file_select_helper->run_from_cef_ = run_from_cef;
file_select_helper->RunFileChooser(render_frame_host, std::move(listener),
params.Clone());
}
@@ -592,7 +627,8 @@ void FileSelectHelper::RunFileChooser(
}
void FileSelectHelper::GetFileTypesInThreadPool(FileChooserParamsPtr params) {
- select_file_types_ = GetFileTypesFromAcceptType(params->accept_types);
+ select_file_types_ = GetFileTypesFromAcceptType(params->accept_types,
+ run_from_cef_);
select_file_types_->allowed_paths =
params->need_local_path ? ui::SelectFileDialog::FileTypeInfo::NATIVE_PATH
: ui::SelectFileDialog::FileTypeInfo::ANY_PATH;
diff --git chrome/browser/file_select_helper.h chrome/browser/file_select_helper.h
index f9d1f31b36357..122e1ce9fa962 100644
--- chrome/browser/file_select_helper.h
+++ chrome/browser/file_select_helper.h
@@ -59,7 +59,8 @@ class FileSelectHelper : public base::RefCountedThreadSafe<
static void RunFileChooser(
content::RenderFrameHost* render_frame_host,
scoped_refptr<content::FileSelectListener> listener,
- const blink::mojom::FileChooserParams& params);
+ const blink::mojom::FileChooserParams& params,
+ bool run_from_cef = false);
// Enumerates all the files in directory.
static void EnumerateDirectory(
@@ -255,7 +256,8 @@ class FileSelectHelper : public base::RefCountedThreadSafe<
// |accept_types| contains only valid lowercased MIME types or file extensions
// beginning with a period (.).
static std::unique_ptr<ui::SelectFileDialog::FileTypeInfo>
- GetFileTypesFromAcceptType(const std::vector<std::u16string>& accept_types);
+ GetFileTypesFromAcceptType(const std::vector<std::u16string>& accept_types,
+ bool run_from_cef);
// Check the accept type is valid. It is expected to be all lower case with
// no whitespace.
@@ -319,6 +321,9 @@ class FileSelectHelper : public base::RefCountedThreadSafe<
// Set to false in unit tests since there is no WebContents.
bool abort_on_missing_web_contents_in_tests_ = true;
+
+ // Set to true if this dialog was triggered via CEF.
+ bool run_from_cef_ = false;
};
#endif // CHROME_BROWSER_FILE_SELECT_HELPER_H_
diff --git chrome/browser/ui/chrome_select_file_policy.h chrome/browser/ui/chrome_select_file_policy.h
index 2cf473c35b67a..e3552bd0f17d4 100644
--- chrome/browser/ui/chrome_select_file_policy.h
+++ chrome/browser/ui/chrome_select_file_policy.h
@@ -30,6 +30,8 @@ class ChromeSelectFilePolicy : public ui::SelectFilePolicy {
// Returns true if local state allows showing file pickers.
static bool FileSelectDialogsAllowed();
+ content::WebContents* source_contents() const { return source_contents_; }
+
private:
raw_ptr<content::WebContents> source_contents_;
};
diff --git printing/printing_context_linux.cc printing/printing_context_linux.cc
index 204cec8311bec..b2d7e16614e15 100644
--- printing/printing_context_linux.cc
+++ printing/printing_context_linux.cc
@@ -54,20 +54,23 @@ PrintingContextLinux::~PrintingContextLinux() {
}
// static
-void PrintingContextLinux::SetCreatePrintDialogFunction(
- PrintDialogGtkInterface* (*create_dialog_func)(
- PrintingContextLinux* context)) {
+PrintingContextLinux::CreatePrintDialogFunctionPtr
+PrintingContextLinux::SetCreatePrintDialogFunction(
+ CreatePrintDialogFunctionPtr create_dialog_func) {
DCHECK(create_dialog_func);
- DCHECK(!create_dialog_func_);
+ auto old_func = create_dialog_func_;
create_dialog_func_ = create_dialog_func;
+ return old_func;
}
// static
-void PrintingContextLinux::SetPdfPaperSizeFunction(
- gfx::Size (*get_pdf_paper_size)(PrintingContextLinux* context)) {
+PrintingContextLinux::PdfPaperSizeFunctionPtr
+PrintingContextLinux::SetPdfPaperSizeFunction(
+ PdfPaperSizeFunctionPtr get_pdf_paper_size) {
DCHECK(get_pdf_paper_size);
- DCHECK(!get_pdf_paper_size_);
+ auto old_func = get_pdf_paper_size_;
get_pdf_paper_size_ = get_pdf_paper_size;
+ return old_func;
}
void PrintingContextLinux::AskUserForSettings(int max_pages,
diff --git printing/printing_context_linux.h printing/printing_context_linux.h
index 653170ba60e83..677df89f93e8d 100644
--- printing/printing_context_linux.h
+++ printing/printing_context_linux.h
@@ -25,12 +25,17 @@ class COMPONENT_EXPORT(PRINTING) PrintingContextLinux : public PrintingContext {
~PrintingContextLinux() override;
// Sets the function that creates the print dialog.
- static void SetCreatePrintDialogFunction(PrintDialogGtkInterface* (
- *create_dialog_func)(PrintingContextLinux* context));
+ // Returns the old function, if any.
+ using CreatePrintDialogFunctionPtr =
+ PrintDialogGtkInterface* (*)(PrintingContextLinux* context);
+ static CreatePrintDialogFunctionPtr SetCreatePrintDialogFunction(
+ CreatePrintDialogFunctionPtr);
// Sets the function that returns pdf paper size through the native API.
- static void SetPdfPaperSizeFunction(
- gfx::Size (*get_pdf_paper_size)(PrintingContextLinux* context));
+ // Returns the old function, if any.
+ using PdfPaperSizeFunctionPtr = gfx::Size (*)(PrintingContextLinux* context);
+ static PdfPaperSizeFunctionPtr SetPdfPaperSizeFunction(
+ PdfPaperSizeFunctionPtr);
// Initializes with predefined settings.
void InitWithSettings(std::unique_ptr<PrintSettings> settings);
diff --git ui/shell_dialogs/execute_select_file_win.cc ui/shell_dialogs/execute_select_file_win.cc
index 063d4c7c96cba..24bd0533af65b 100644
--- ui/shell_dialogs/execute_select_file_win.cc
+++ ui/shell_dialogs/execute_select_file_win.cc
@@ -289,9 +289,7 @@ bool ExecuteSelectSingleFile(HWND owner,
const std::vector<FileFilterSpec>& filter,
int* filter_index,
std::vector<base::FilePath>* paths) {
- // Note: The title is not passed down for historical reasons.
- // TODO(pmonette): Figure out if it's a worthwhile improvement.
- return RunOpenFileDialog(owner, std::u16string(), std::u16string(),
+ return RunOpenFileDialog(owner, title, std::u16string(),
default_path, filter, 0, filter_index, paths);
}
@@ -303,14 +301,13 @@ bool ExecuteSelectMultipleFile(HWND owner,
std::vector<base::FilePath>* paths) {
DWORD dialog_options = FOS_ALLOWMULTISELECT;
- // Note: The title is not passed down for historical reasons.
- // TODO(pmonette): Figure out if it's a worthwhile improvement.
- return RunOpenFileDialog(owner, std::u16string(), std::u16string(),
+ return RunOpenFileDialog(owner, title, std::u16string(),
default_path, filter, dialog_options, filter_index,
paths);
}
bool ExecuteSaveFile(HWND owner,
+ const std::u16string& title,
const base::FilePath& default_path,
const std::vector<FileFilterSpec>& filter,
const std::wstring& def_ext,
@@ -323,9 +320,7 @@ bool ExecuteSaveFile(HWND owner,
DWORD dialog_options = FOS_OVERWRITEPROMPT;
- // Note: The title is not passed down for historical reasons.
- // TODO(pmonette): Figure out if it's a worthwhile improvement.
- return RunSaveFileDialog(owner, std::u16string(), default_path, filter,
+ return RunSaveFileDialog(owner, title, default_path, filter,
dialog_options, def_ext, filter_index, path);
}
@@ -390,7 +385,7 @@ void ExecuteSelectFile(
break;
case SelectFileDialog::SELECT_SAVEAS_FILE: {
base::FilePath path;
- if (ExecuteSaveFile(owner, default_path, filter, default_extension,
+ if (ExecuteSaveFile(owner, title, default_path, filter, default_extension,
&file_type_index, &path)) {
paths.push_back(std::move(path));
}
diff --git ui/shell_dialogs/select_file_dialog.cc ui/shell_dialogs/select_file_dialog.cc
index a622d465ab9e9..b5c11c3117738 100644
--- ui/shell_dialogs/select_file_dialog.cc
+++ ui/shell_dialogs/select_file_dialog.cc
@@ -64,8 +64,10 @@ void SelectFileDialog::SetFactory(ui::SelectFileDialogFactory* factory) {
// static
scoped_refptr<SelectFileDialog> SelectFileDialog::Create(
Listener* listener,
- std::unique_ptr<ui::SelectFilePolicy> policy) {
- if (dialog_factory_)
+ std::unique_ptr<ui::SelectFilePolicy> policy,
+ bool run_from_cef) {
+ // Avoid reentrancy of the CEF factory.
+ if (dialog_factory_ && (!run_from_cef || !dialog_factory_->IsCefFactory()))
return dialog_factory_->Create(listener, std::move(policy));
return CreateSelectFileDialog(listener, std::move(policy));
}
diff --git ui/shell_dialogs/select_file_dialog.h ui/shell_dialogs/select_file_dialog.h
index 8a417fc43a7e4..6d7b065b5b192 100644
--- ui/shell_dialogs/select_file_dialog.h
+++ ui/shell_dialogs/select_file_dialog.h
@@ -111,7 +111,8 @@ class SHELL_DIALOGS_EXPORT SelectFileDialog
// is refcounted and uses a background thread.
static scoped_refptr<SelectFileDialog> Create(
Listener* listener,
- std::unique_ptr<SelectFilePolicy> policy);
+ std::unique_ptr<SelectFilePolicy> policy,
+ bool run_from_cef = false);
SelectFileDialog(const SelectFileDialog&) = delete;
SelectFileDialog& operator=(const SelectFileDialog&) = delete;
@@ -205,6 +206,19 @@ class SHELL_DIALOGS_EXPORT SelectFileDialog
void* params);
bool HasMultipleFileTypeChoices();
+ // Match the types used by CefWindowHandle.
+#if BUILDFLAG(IS_MAC)
+ using WidgetType = void*;
+ static constexpr WidgetType kNullWidget = nullptr;
+#else
+ using WidgetType = gfx::AcceleratedWidget;
+ static constexpr WidgetType kNullWidget = gfx::kNullAcceleratedWidget;
+#endif
+
+ void set_owning_widget(WidgetType widget) {
+ owning_widget_ = widget;
+ }
+
protected:
friend class base::RefCountedThreadSafe<SelectFileDialog>;
@@ -229,6 +243,11 @@ class SHELL_DIALOGS_EXPORT SelectFileDialog
// The listener to be notified of selection completion.
raw_ptr<Listener> listener_;
+ std::unique_ptr<SelectFilePolicy> select_file_policy_;
+
+ // Support override of the |owning_window| value.
+ WidgetType owning_widget_ = kNullWidget;
+
private:
// Tests if the file selection dialog can be displayed by
// testing if the AllowFileSelectionDialogs-Policy is
@@ -241,8 +260,6 @@ class SHELL_DIALOGS_EXPORT SelectFileDialog
// Returns true if the dialog has multiple file type choices.
virtual bool HasMultipleFileTypeChoicesImpl() = 0;
-
- std::unique_ptr<SelectFilePolicy> select_file_policy_;
};
SelectFileDialog* CreateSelectFileDialog(
diff --git ui/shell_dialogs/select_file_dialog_factory.h ui/shell_dialogs/select_file_dialog_factory.h
index 567f50de40b04..1fbac69307bdc 100644
--- ui/shell_dialogs/select_file_dialog_factory.h
+++ ui/shell_dialogs/select_file_dialog_factory.h
@@ -24,6 +24,8 @@ class SHELL_DIALOGS_EXPORT SelectFileDialogFactory {
virtual SelectFileDialog* Create(
ui::SelectFileDialog::Listener* listener,
std::unique_ptr<ui::SelectFilePolicy> policy) = 0;
+
+ virtual bool IsCefFactory() const { return false; }
};
} // namespace ui
diff --git ui/shell_dialogs/select_file_dialog_mac.mm ui/shell_dialogs/select_file_dialog_mac.mm
index 605c2278407ce..26ca067d32720 100644
--- ui/shell_dialogs/select_file_dialog_mac.mm
+++ ui/shell_dialogs/select_file_dialog_mac.mm
@@ -100,6 +100,10 @@ void SelectFileDialogImpl::SelectFileImpl(
mojo_window->CreateSelectFileDialog(std::move(receiver));
} else {
NSWindow* ns_window = gfx_window.GetNativeNSWindow();
+ if (!ns_window && owning_widget_) {
+ NSView* view = ((__bridge NSView*)owning_widget_);
+ ns_window = [view window];
+ }
mojo::MakeSelfOwnedReceiver(
std::make_unique<remote_cocoa::SelectFileDialogBridge>(ns_window),
std::move(receiver));
diff --git ui/shell_dialogs/select_file_dialog_win.cc ui/shell_dialogs/select_file_dialog_win.cc
index e2959960598a2..477992b18730b 100644
--- ui/shell_dialogs/select_file_dialog_win.cc
+++ ui/shell_dialogs/select_file_dialog_win.cc
@@ -248,6 +248,8 @@ void SelectFileDialogImpl::SelectFileImpl(
HWND owner = owning_window && owning_window->GetRootWindow()
? owning_window->GetHost()->GetAcceleratedWidget()
: nullptr;
+ if (!owner)
+ owner = owning_widget_;
std::unique_ptr<RunState> run_state = BeginRun(owner);

View File

@ -1,145 +0,0 @@
diff --git chrome/browser/ui/BUILD.gn chrome/browser/ui/BUILD.gn
index 936021a313995..2dd2554f8a7c5 100644
--- chrome/browser/ui/BUILD.gn
+++ chrome/browser/ui/BUILD.gn
@@ -10,6 +10,7 @@ import("//build/config/features.gni")
import("//build/config/linux/gtk/gtk.gni")
import("//build/config/ozone.gni")
import("//build/config/ui.gni")
+import("//cef/libcef/features/features.gni")
import("//chrome/browser/buildflags.gni")
import("//chrome/common/features.gni")
import("//chromeos/assistant/assistant.gni")
@@ -353,6 +354,10 @@ static_library("ui") {
"//build/config/compiler:wexit_time_destructors",
]
+ if (enable_cef) {
+ configs += [ "//cef/libcef/features:config" ]
+ }
+
# Since browser and browser_ui actually depend on each other,
# we must omit the dependency from browser_ui to browser.
# However, this means browser_ui and browser should more or less
@@ -375,6 +380,7 @@ static_library("ui") {
"//build:branding_buildflags",
"//build:chromeos_buildflags",
"//cc/paint",
+ "//cef/libcef/features",
"//chrome:extra_resources",
"//chrome:resources",
"//chrome:strings",
@@ -5301,6 +5307,7 @@ static_library("ui") {
if (enable_basic_printing) {
deps += [
"//components/printing/browser",
+ "//components/printing/common:mojo_interfaces",
"//printing",
]
}
diff --git chrome/browser/ui/webui/net_export_ui.cc chrome/browser/ui/webui/net_export_ui.cc
index 12edced619355..3a1eb1461ab08 100644
--- chrome/browser/ui/webui/net_export_ui.cc
+++ chrome/browser/ui/webui/net_export_ui.cc
@@ -22,6 +22,7 @@
#include "base/task/single_thread_task_runner.h"
#include "base/values.h"
#include "build/build_config.h"
+#include "cef/libcef/features/runtime.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/download/download_prefs.h"
#include "chrome/browser/net/net_export_helper.h"
@@ -45,6 +46,10 @@
#include "net/log/net_log_capture_mode.h"
#include "ui/shell_dialogs/select_file_dialog.h"
+#if BUILDFLAG(ENABLE_CEF)
+#include "cef/libcef/browser/alloy/alloy_dialog_util.h"
+#endif
+
#if BUILDFLAG(IS_ANDROID)
#include "components/browser_ui/share/android/intent_helper.h"
#endif
@@ -142,6 +147,13 @@ class NetExportMessageHandler
// NetLog file.
void ShowSelectFileDialog(const base::FilePath& default_path);
+#if BUILDFLAG(ENABLE_CEF)
+ void ShowCefSaveAsDialog(content::WebContents* web_contents);
+ void SaveAsDialogDismissed(
+ int selected_accept_filter,
+ const std::vector<base::FilePath>& file_paths);
+#endif
+
// Cached pointer to SystemNetworkContextManager's NetExportFileWriter.
raw_ptr<net_log::NetExportFileWriter> file_writer_;
@@ -235,6 +247,13 @@ void NetExportMessageHandler::OnStartNetLog(const base::ListValue* list) {
if (UsingMobileUI()) {
StartNetLog(base::FilePath());
} else {
+#if BUILDFLAG(ENABLE_CEF)
+ if (cef::IsAlloyRuntimeEnabled()) {
+ ShowCefSaveAsDialog(web_ui()->GetWebContents());
+ return;
+ }
+#endif
+
base::FilePath initial_dir = last_save_dir.Pointer()->empty() ?
DownloadPrefs::FromBrowserContext(
web_ui()->GetWebContents()->GetBrowserContext())->DownloadPath() :
@@ -251,6 +270,7 @@ void NetExportMessageHandler::OnStopNetLog(const base::ListValue* list) {
std::unique_ptr<base::DictionaryValue> ui_thread_polled_data(
new base::DictionaryValue());
+ if (!cef::IsAlloyRuntimeEnabled()) {
Profile* profile = Profile::FromWebUI(web_ui());
SetIfNotNull(ui_thread_polled_data.get(), "prerenderInfo",
chrome_browser_net::GetPrerenderInfo(profile));
@@ -260,6 +280,7 @@ void NetExportMessageHandler::OnStopNetLog(const base::ListValue* list) {
SetIfNotNull(ui_thread_polled_data.get(), "serviceProviders",
chrome_browser_net::GetWindowsServiceProviders());
#endif
+ }
file_writer_->StopNetLog(std::move(ui_thread_polled_data));
}
@@ -375,6 +396,38 @@ void NetExportMessageHandler::ShowSelectFileDialog(
&file_type_info, 0, base::FilePath::StringType(), owning_window, nullptr);
}
+#if BUILDFLAG(ENABLE_CEF)
+
+void NetExportMessageHandler::ShowCefSaveAsDialog(
+ content::WebContents* web_contents) {
+ base::FilePath initial_dir;
+ if (!last_save_dir.Pointer()->empty())
+ initial_dir = *last_save_dir.Pointer();
+ base::FilePath initial_path =
+ initial_dir.Append(FILE_PATH_LITERAL("chrome-net-export-log.json"));
+
+ blink::mojom::FileChooserParams params;
+ params.mode = blink::mojom::FileChooserParams::Mode::kSave;
+ params.default_file_name = initial_path;
+ params.accept_types.push_back(
+ alloy::FilePathTypeToString16(initial_path.Extension()));
+
+ alloy::RunFileChooser(web_contents, params,
+ base::BindOnce(&NetExportMessageHandler::SaveAsDialogDismissed,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void NetExportMessageHandler::SaveAsDialogDismissed(
+ int selected_accept_filter,
+ const std::vector<base::FilePath>& file_paths) {
+ if (file_paths.size() == 1) {
+ *last_save_dir.Pointer() = file_paths[0].DirName();
+ StartNetLog(file_paths[0]);
+ }
+}
+
+#endif // BUILDFLAG(ENABLE_CEF)
+
} // namespace
NetExportUI::NetExportUI(content::WebUI* web_ui) : WebUIController(web_ui) {

View File

@ -135,159 +135,6 @@ index f6098966f5b34..da78289b66155 100644
#endif
}
diff --git chrome/browser/ui/webui/print_preview/pdf_printer_handler.cc chrome/browser/ui/webui/print_preview/pdf_printer_handler.cc
index 86e16795ce43d..9053975ad42f6 100644
--- chrome/browser/ui/webui/print_preview/pdf_printer_handler.cc
+++ chrome/browser/ui/webui/print_preview/pdf_printer_handler.cc
@@ -21,6 +21,7 @@
#include "base/values.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
+#include "cef/libcef/features/runtime.h"
#include "chrome/browser/app_mode/app_mode_utils.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/download/download_prefs.h"
@@ -62,6 +63,10 @@
#include "chromeos/lacros/lacros_service.h"
#endif
+#if BUILDFLAG(ENABLE_CEF)
+#include "cef/libcef/browser/alloy/alloy_dialog_util.h"
+#endif
+
namespace printing {
namespace {
@@ -414,16 +419,18 @@ void PdfPrinterHandler::SelectFile(const base::FilePath& default_filename,
service->GetRemote<crosapi::mojom::DriveIntegrationService>()
->GetMountPointPath(
base::BindOnce(&PdfPrinterHandler::OnSaveLocationReady,
- weak_ptr_factory_.GetWeakPtr(),
+ weak_ptr_factory_.GetWeakPtr(), initiator,
std::move(default_filename), prompt_user));
return;
}
#endif
- OnSaveLocationReady(default_filename, prompt_user, GetSaveLocation());
+ OnSaveLocationReady(initiator, default_filename, prompt_user,
+ GetSaveLocation());
}
void PdfPrinterHandler::OnSaveLocationReady(
+ content::WebContents* initiator,
const base::FilePath& default_filename,
bool prompt_user,
const base::FilePath& path) {
@@ -441,10 +448,27 @@ void PdfPrinterHandler::OnSaveLocationReady(
// If the directory is empty there is no reason to create it or use the
// default location.
if (path.empty()) {
+#if BUILDFLAG(ENABLE_CEF)
+ if (cef::IsAlloyRuntimeEnabled()) {
+ ShowCefSaveAsDialog(initiator, default_filename, path);
+ return;
+ }
+#endif
OnDirectorySelected(default_filename, path);
return;
}
+ auto callback = base::BindOnce(&PdfPrinterHandler::OnDirectorySelected,
+ weak_ptr_factory_.GetWeakPtr(),
+ default_filename);
+#if BUILDFLAG(ENABLE_CEF)
+ if (cef::IsAlloyRuntimeEnabled()) {
+ callback = base::BindOnce(&PdfPrinterHandler::ShowCefSaveAsDialog,
+ weak_ptr_factory_.GetWeakPtr(), initiator,
+ default_filename);
+ }
+#endif
+
// Get default download directory. This will be used as a fallback if the
// save directory does not exist.
DownloadPrefs* download_prefs = DownloadPrefs::FromBrowserContext(profile_);
@@ -452,8 +476,7 @@ void PdfPrinterHandler::OnSaveLocationReady(
base::ThreadPool::PostTaskAndReplyWithResult(
FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT},
base::BindOnce(&SelectSaveDirectory, path, default_path),
- base::BindOnce(&PdfPrinterHandler::OnDirectorySelected,
- weak_ptr_factory_.GetWeakPtr(), default_filename));
+ std::move(callback));
}
void PdfPrinterHandler::PostPrintToPdfTask() {
@@ -499,6 +522,36 @@ void PdfPrinterHandler::OnDirectorySelected(const base::FilePath& filename,
platform_util::GetTopLevel(preview_web_contents_->GetNativeView()), NULL);
}
+#if BUILDFLAG(ENABLE_CEF)
+
+void PdfPrinterHandler::ShowCefSaveAsDialog(content::WebContents* initiator,
+ const base::FilePath& filename,
+ const base::FilePath& directory) {
+ base::FilePath path = directory.Append(filename);
+
+ blink::mojom::FileChooserParams params;
+ params.mode = blink::mojom::FileChooserParams::Mode::kSave;
+ params.default_file_name = path;
+ params.accept_types.push_back(
+ alloy::FilePathTypeToString16(path.Extension()));
+
+ alloy::RunFileChooser(initiator, params,
+ base::BindOnce(&PdfPrinterHandler::SaveAsDialogDismissed,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void PdfPrinterHandler::SaveAsDialogDismissed(
+ int selected_accept_filter,
+ const std::vector<base::FilePath>& file_paths) {
+ if (file_paths.size() == 1) {
+ FileSelected(file_paths[0], 0, nullptr);
+ } else {
+ FileSelectionCanceled(nullptr);
+ }
+}
+
+#endif // BUILDFLAG(ENABLE_CEF)
+
base::FilePath PdfPrinterHandler::GetSaveLocation() const {
#if BUILDFLAG(IS_CHROMEOS_ASH)
drive::DriveIntegrationService* drive_service =
diff --git chrome/browser/ui/webui/print_preview/pdf_printer_handler.h chrome/browser/ui/webui/print_preview/pdf_printer_handler.h
index 46c8b1d08b075..1ee95cd7c3240 100644
--- chrome/browser/ui/webui/print_preview/pdf_printer_handler.h
+++ chrome/browser/ui/webui/print_preview/pdf_printer_handler.h
@@ -12,6 +12,7 @@
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "build/chromeos_buildflags.h"
+#include "cef/libcef/features/features.h"
#include "chrome/browser/ui/webui/print_preview/printer_handler.h"
#include "ui/shell_dialogs/select_file_dialog.h"
@@ -95,10 +96,20 @@ class PdfPrinterHandler : public PrinterHandler,
void OnDirectorySelected(const base::FilePath& filename,
const base::FilePath& directory);
- void OnSaveLocationReady(const base::FilePath& default_filename,
+ void OnSaveLocationReady(content::WebContents* initiator,
+ const base::FilePath& default_filename,
bool prompt_user,
const base::FilePath& path);
+#if BUILDFLAG(ENABLE_CEF)
+ void ShowCefSaveAsDialog(content::WebContents* initiator,
+ const base::FilePath& filename,
+ const base::FilePath& directory);
+
+ void SaveAsDialogDismissed(int selected_accept_filter,
+ const std::vector<base::FilePath>& file_paths);
+#endif
+
// Return save location as the Drive mount or fetch from Download Preferences.
base::FilePath GetSaveLocation() const;
diff --git chrome/browser/ui/webui/print_preview/print_preview_ui.cc chrome/browser/ui/webui/print_preview/print_preview_ui.cc
index eba14d78d87ff..7901f000a44b5 100644
--- chrome/browser/ui/webui/print_preview/print_preview_ui.cc

View File

@ -260,12 +260,6 @@ ClientHandler::ClientHandler(Delegate* delegate,
initial_navigation_(true) {
DCHECK(!console_log_file_.empty());
#if defined(OS_LINUX)
// Provide the GTK-based dialog implementation on Linux.
dialog_handler_ = new ClientDialogHandlerGtk();
print_handler_ = new ClientPrintHandlerGtk();
#endif
resource_manager_ = new CefResourceManager();
test_runner::SetupResourceManager(resource_manager_, &string_resource_map_);
@ -275,6 +269,34 @@ ClientHandler::ClientHandler(Delegate* delegate,
mouse_cursor_change_disabled_ =
command_line->HasSwitch(switches::kMouseCursorChangeDisabled);
offline_ = command_line->HasSwitch(switches::kOffline);
#if defined(OS_LINUX)
// Optionally use the client-provided dialog implementation.
bool use_client_dialogs =
command_line->HasSwitch(switches::kUseClientDialogs);
if (!use_client_dialogs &&
command_line->HasSwitch(switches::kMultiThreadedMessageLoop)) {
// Default dialogs are not supported in combination with
// multi-threaded-message-loop because Chromium doesn't support GDK threads
// internally.
LOG(WARNING) << "Client dialogs must be used in combination with "
"multi-threaded-message-loop.";
use_client_dialogs = true;
}
if (use_client_dialogs && MainContext::Get()->UseViews()) {
// Client dialogs cannot be used in combination with Views because the
// implementation of ClientDialogHandlerGtk requires a top-level GtkWindow.
LOG(ERROR) << "Client dialogs cannot be used in combination with Views.";
use_client_dialogs = false;
}
if (use_client_dialogs) {
dialog_handler_ = new ClientDialogHandlerGtk();
print_handler_ = new ClientPrintHandlerGtk();
}
#endif // defined(OS_LINUX)
}
void ClientHandler::DetachDelegate() {

View File

@ -136,6 +136,7 @@ GtkWindow* GetWindow(CefRefPtr<CefBrowser> browser) {
RootWindow::GetForBrowser(browser->GetIdentifier());
if (root_window) {
GtkWidget* window = root_window->GetWindowHandle();
DCHECK(window);
if (!window)
LOG(ERROR) << "No GtkWindow for browser";
return GTK_WINDOW(window);
@ -153,7 +154,6 @@ bool ClientDialogHandlerGtk::OnFileDialog(
const CefString& title,
const CefString& default_file_path,
const std::vector<CefString>& accept_filters,
int selected_accept_filter,
CefRefPtr<CefFileDialogCallback> callback) {
CEF_REQUIRE_UI_THREAD();
@ -163,7 +163,6 @@ bool ClientDialogHandlerGtk::OnFileDialog(
params.title = title;
params.default_file_path = default_file_path;
params.accept_filters = accept_filters;
params.selected_accept_filter = selected_accept_filter;
params.callback = callback;
GetWindowAndContinue(
@ -221,8 +220,9 @@ void ClientDialogHandlerGtk::OnResetDialogState(CefRefPtr<CefBrowser> browser) {
js_dialog_callback_ = nullptr;
}
void ClientDialogHandlerGtk::OnFileDialogContinue(OnFileDialogParams params,
GtkWindow* window) {
void ClientDialogHandlerGtk::OnFileDialogContinue(
const OnFileDialogParams& params,
GtkWindow* window) {
REQUIRE_MAIN_THREAD();
ScopedGdkThreadsEnter scoped_gdk_threads;
@ -232,17 +232,14 @@ void ClientDialogHandlerGtk::OnFileDialogContinue(OnFileDialogParams params,
GtkFileChooserAction action;
const gchar* accept_button;
// Remove any modifier flags.
FileDialogMode mode_type =
static_cast<FileDialogMode>(params.mode & FILE_DIALOG_TYPE_MASK);
if (mode_type == FILE_DIALOG_OPEN || mode_type == FILE_DIALOG_OPEN_MULTIPLE) {
if (params.mode == FILE_DIALOG_OPEN ||
params.mode == FILE_DIALOG_OPEN_MULTIPLE) {
action = GTK_FILE_CHOOSER_ACTION_OPEN;
accept_button = "_Open";
} else if (mode_type == FILE_DIALOG_OPEN_FOLDER) {
} else if (params.mode == FILE_DIALOG_OPEN_FOLDER) {
action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
accept_button = "_Open";
} else if (mode_type == FILE_DIALOG_SAVE) {
} else if (params.mode == FILE_DIALOG_SAVE) {
action = GTK_FILE_CHOOSER_ACTION_SAVE;
accept_button = "_Save";
} else {
@ -255,7 +252,7 @@ void ClientDialogHandlerGtk::OnFileDialogContinue(OnFileDialogParams params,
if (!params.title.empty()) {
title_str = params.title;
} else {
switch (mode_type) {
switch (params.mode) {
case FILE_DIALOG_OPEN:
title_str = "Open File";
break;
@ -277,19 +274,10 @@ void ClientDialogHandlerGtk::OnFileDialogContinue(OnFileDialogParams params,
title_str.c_str(), GTK_WINDOW(window), action, "_Cancel",
GTK_RESPONSE_CANCEL, accept_button, GTK_RESPONSE_ACCEPT, nullptr);
if (mode_type == FILE_DIALOG_OPEN_MULTIPLE)
if (params.mode == FILE_DIALOG_OPEN_MULTIPLE)
gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), TRUE);
if (mode_type == FILE_DIALOG_SAVE) {
gtk_file_chooser_set_do_overwrite_confirmation(
GTK_FILE_CHOOSER(dialog),
!!(params.mode & FILE_DIALOG_OVERWRITEPROMPT_FLAG));
}
gtk_file_chooser_set_show_hidden(
GTK_FILE_CHOOSER(dialog), !(params.mode & FILE_DIALOG_HIDEREADONLY_FLAG));
if (!params.default_file_path.empty() && mode_type == FILE_DIALOG_SAVE) {
if (!params.default_file_path.empty() && params.mode == FILE_DIALOG_SAVE) {
const std::string& file_path = params.default_file_path;
bool exists = false;
@ -310,20 +298,17 @@ void ClientDialogHandlerGtk::OnFileDialogContinue(OnFileDialogParams params,
std::vector<GtkFileFilter*> filters;
AddFilters(GTK_FILE_CHOOSER(dialog), params.accept_filters, true, &filters);
if (params.selected_accept_filter < static_cast<int>(filters.size())) {
gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog),
filters[params.selected_accept_filter]);
}
bool success = false;
if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
if (mode_type == FILE_DIALOG_OPEN || mode_type == FILE_DIALOG_OPEN_FOLDER ||
mode_type == FILE_DIALOG_SAVE) {
if (params.mode == FILE_DIALOG_OPEN ||
params.mode == FILE_DIALOG_OPEN_FOLDER ||
params.mode == FILE_DIALOG_SAVE) {
char* filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
files.push_back(std::string(filename));
success = true;
} else if (mode_type == FILE_DIALOG_OPEN_MULTIPLE) {
} else if (params.mode == FILE_DIALOG_OPEN_MULTIPLE) {
GSList* filenames =
gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog));
if (filenames) {
@ -339,29 +324,15 @@ void ClientDialogHandlerGtk::OnFileDialogContinue(OnFileDialogParams params,
}
}
int filter_index = params.selected_accept_filter;
if (success) {
GtkFileFilter* selected_filter =
gtk_file_chooser_get_filter(GTK_FILE_CHOOSER(dialog));
if (selected_filter != nullptr) {
for (size_t x = 0; x < filters.size(); ++x) {
if (filters[x] == selected_filter) {
filter_index = x;
break;
}
}
}
}
gtk_widget_destroy(dialog);
if (success)
params.callback->Continue(filter_index, files);
params.callback->Continue(files);
else
params.callback->Cancel();
}
void ClientDialogHandlerGtk::OnJSDialogContinue(OnJSDialogParams params,
void ClientDialogHandlerGtk::OnJSDialogContinue(const OnJSDialogParams& params,
GtkWindow* window) {
REQUIRE_MAIN_THREAD();

View File

@ -25,7 +25,6 @@ class ClientDialogHandlerGtk : public CefDialogHandler,
const CefString& title,
const CefString& default_file_path,
const std::vector<CefString>& accept_filters,
int selected_accept_filter,
CefRefPtr<CefFileDialogCallback> callback) override;
// CefJSDialogHandler methods.
@ -49,10 +48,10 @@ class ClientDialogHandlerGtk : public CefDialogHandler,
CefString title;
CefString default_file_path;
std::vector<CefString> accept_filters;
int selected_accept_filter;
CefRefPtr<CefFileDialogCallback> callback;
};
void OnFileDialogContinue(OnFileDialogParams params, GtkWindow* window);
void OnFileDialogContinue(const OnFileDialogParams& params,
GtkWindow* window);
struct OnJSDialogParams {
CefRefPtr<CefBrowser> browser;
@ -62,7 +61,7 @@ class ClientDialogHandlerGtk : public CefDialogHandler,
CefString default_prompt_text;
CefRefPtr<CefJSDialogCallback> callback;
};
void OnJSDialogContinue(OnJSDialogParams params, GtkWindow* window);
void OnJSDialogContinue(const OnJSDialogParams& params, GtkWindow* window);
void GetWindowAndContinue(CefRefPtr<CefBrowser> browser,
base::OnceCallback<void(GtkWindow*)> callback);

View File

@ -17,7 +17,8 @@ namespace dialog_test {
namespace {
const char kTestUrlPath[] = "/dialogs";
const char kFileOpenMessageName[] = "DialogTest.FileOpen";
const char kFileOpenPngMessageName[] = "DialogTest.FileOpenPng";
const char kFileOpenImageMessageName[] = "DialogTest.FileOpenImage";
const char kFileOpenMultipleMessageName[] = "DialogTest.FileOpenMultiple";
const char kFileOpenFolderMessageName[] = "DialogTest.FileOpenFolder";
const char kFileSaveMessageName[] = "DialogTest.FileSave";
@ -25,11 +26,9 @@ const char kFileSaveMessageName[] = "DialogTest.FileSave";
// Store persistent dialog state information.
class DialogState : public base::RefCountedThreadSafe<DialogState> {
public:
DialogState()
: mode_(FILE_DIALOG_OPEN), last_selected_filter_(0), pending_(false) {}
DialogState() : mode_(FILE_DIALOG_OPEN), pending_(false) {}
cef_file_dialog_mode_t mode_;
int last_selected_filter_;
CefString last_file_;
bool pending_;
@ -45,15 +44,11 @@ class DialogCallback : public CefRunFileDialogCallback {
: router_callback_(router_callback), dialog_state_(dialog_state) {}
virtual void OnFileDialogDismissed(
int last_selected_filter,
const std::vector<CefString>& file_paths) override {
CEF_REQUIRE_UI_THREAD();
DCHECK(dialog_state_->pending_);
if (!file_paths.empty()) {
if (dialog_state_->mode_ != FILE_DIALOG_OPEN_FOLDER)
dialog_state_->last_selected_filter_ = last_selected_filter;
dialog_state_->last_file_ = file_paths[0];
if (dialog_state_->mode_ == FILE_DIALOG_OPEN_FOLDER) {
std::string last_file = dialog_state_->last_file_;
@ -118,25 +113,30 @@ class Handler : public CefMessageRouterBrowserSide::Handler {
std::string title;
const std::string& message_name = request;
if (message_name == kFileOpenMessageName) {
if (message_name == kFileOpenPngMessageName) {
dialog_state_->mode_ = FILE_DIALOG_OPEN;
title = "My Open Dialog";
title = "My Open PNG Dialog";
accept_filters.push_back(".png");
} else if (message_name == kFileOpenImageMessageName) {
dialog_state_->mode_ = FILE_DIALOG_OPEN;
title = "My Open Image Dialog";
accept_filters.push_back("image/*");
} else if (message_name == kFileOpenMultipleMessageName) {
dialog_state_->mode_ = FILE_DIALOG_OPEN_MULTIPLE;
title = "My Open Multiple Dialog";
title = "My Open MultiType Dialog";
} else if (message_name == kFileOpenFolderMessageName) {
dialog_state_->mode_ = FILE_DIALOG_OPEN_FOLDER;
title = "My Open Folder Dialog";
} else if (message_name == kFileSaveMessageName) {
dialog_state_->mode_ = static_cast<cef_file_dialog_mode_t>(
FILE_DIALOG_SAVE | FILE_DIALOG_OVERWRITEPROMPT_FLAG);
dialog_state_->mode_ = FILE_DIALOG_SAVE;
title = "My Save Dialog";
} else {
NOTREACHED();
return true;
}
if (dialog_state_->mode_ != FILE_DIALOG_OPEN_FOLDER) {
if (accept_filters.empty() &&
dialog_state_->mode_ != FILE_DIALOG_OPEN_FOLDER) {
// Build filters based on mime time.
accept_filters.push_back("text/*");
@ -154,7 +154,6 @@ class Handler : public CefMessageRouterBrowserSide::Handler {
browser->GetHost()->RunFileDialog(
dialog_state_->mode_, title, dialog_state_->last_file_, accept_filters,
dialog_state_->last_selected_filter_,
new DialogCallback(callback, dialog_state_));
return true;

View File

@ -312,17 +312,12 @@ void EndTracing(CefRefPtr<CefBrowser> browser) {
// Results in a call to OnFileDialogDismissed.
browser_->GetHost()->RunFileDialog(
static_cast<cef_file_dialog_mode_t>(FILE_DIALOG_SAVE |
FILE_DIALOG_OVERWRITEPROMPT_FLAG),
CefString(), // title
path,
std::vector<CefString>(), // accept_filters
0, // selected_accept_filter
this);
FILE_DIALOG_SAVE,
/*title=*/CefString(), path,
/*accept_filters=*/std::vector<CefString>(), this);
}
void OnFileDialogDismissed(
int selected_accept_filter,
const std::vector<CefString>& file_paths) override {
if (!file_paths.empty()) {
// File selected. Results in a call to OnEndTracingComplete.
@ -370,17 +365,12 @@ void PrintToPDF(CefRefPtr<CefBrowser> browser) {
accept_filters.push_back(".pdf");
// Results in a call to OnFileDialogDismissed.
browser_->GetHost()->RunFileDialog(
static_cast<cef_file_dialog_mode_t>(FILE_DIALOG_SAVE |
FILE_DIALOG_OVERWRITEPROMPT_FLAG),
CefString(), // title
path, accept_filters,
0, // selected_accept_filter
this);
browser_->GetHost()->RunFileDialog(FILE_DIALOG_SAVE,
/*title=*/CefString(), path,
accept_filters, this);
}
void OnFileDialogDismissed(
int selected_accept_filter,
const std::vector<CefString>& file_paths) override {
if (!file_paths.empty()) {
CefPdfPrintSettings settings;

View File

@ -65,10 +65,13 @@ Click a button to show the associated dialog type.
<br/><input type="button" onclick="show_alert();" value="Show Alert">
<br/><input type="button" onclick="show_confirm();" value="Show Confirm"> <span id="cm"></span>
<br/><input type="button" onclick="show_prompt();" value="Show Prompt"> <span id="pm"></span>
<br/>input type="file": <input type="file" name="pic" accept="text/*,.js,.css,image/*">
<br/>input type="file" (.png): <input type="file" name="pic" accept=".png">
<br/>input type="file" (image/*): <input type="file" name="pic" accept="image/*">
<br/>input type="file" (multiple types): <input type="file" name="pic" accept="text/*,.js,.css,image/*">
<br/>input type="file" (directory): <input type="file" webkitdirectory accept="text/*,.js,.css,image/*">
<br/><input type="button" onclick="show_file_dialog('fo', 'FileOpen');" value="Show File Open" disabled="true"> <span id="fo"></span>
<br/><input type="button" onclick="show_file_dialog('fom', 'FileOpenMultiple');" value="Show File Open Multiple" disabled="true"> <span id="fom"></span>
<br/><input type="button" onclick="show_file_dialog('fop', 'FileOpenPng');" value="Show File Open (.png)" disabled="true"> <span id="fop"></span>
<br/><input type="button" onclick="show_file_dialog('foi', 'FileOpenImage');" value="Show File Open (image/*)" disabled="true"> <span id="foi"></span>
<br/><input type="button" onclick="show_file_dialog('fom', 'FileOpenMultiple');" value="Show File Open (multiple types/files)" disabled="true"> <span id="fom"></span>
<br/><input type="button" onclick="show_file_dialog('fof', 'FileOpenFolder');" value="Show File Open Folder" disabled="true"> <span id="fof"></span>
<br/><input type="button" onclick="show_file_dialog('fs', 'FileSave');" value="Show File Save" disabled="true"> <span id="fs"></span>
<p id="time"></p>

View File

@ -19,7 +19,6 @@ class DialogTestHandler : public TestHandler {
: mode(dialog_mode),
title("Test Title"),
default_file_name("Test File Name"),
selected_accept_filter(1), // Something other than 0 for testing.
callback_async(false),
callback_cancel(false) {
accept_types.push_back("text/*");
@ -31,7 +30,6 @@ class DialogTestHandler : public TestHandler {
CefString title;
CefString default_file_name;
std::vector<CefString> accept_types;
int selected_accept_filter;
bool callback_async; // True if the callback should execute asynchronously.
bool callback_cancel; // True if the callback should cancel.
@ -43,16 +41,12 @@ class DialogTestHandler : public TestHandler {
explicit Callback(DialogTestHandler* handler) : handler_(handler) {}
void OnFileDialogDismissed(
int selected_accept_filter,
const std::vector<CefString>& file_paths) override {
handler_->got_onfiledialogdismissed_.yes();
if (handler_->config_.callback_cancel) {
EXPECT_EQ(0, selected_accept_filter);
EXPECT_TRUE(file_paths.empty());
} else {
EXPECT_EQ(handler_->config_.selected_accept_filter,
selected_accept_filter);
TestStringVectorEqual(handler_->config_.callback_paths, file_paths);
}
@ -81,18 +75,16 @@ class DialogTestHandler : public TestHandler {
void OnLoadEnd(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
int httpStatusCode) override {
browser->GetHost()->RunFileDialog(
config_.mode, config_.title, config_.default_file_name,
config_.accept_types, config_.selected_accept_filter,
new Callback(this));
browser->GetHost()->RunFileDialog(config_.mode, config_.title,
config_.default_file_name,
config_.accept_types, new Callback(this));
}
void ExecuteCallback(CefRefPtr<CefFileDialogCallback> callback) {
if (config_.callback_cancel)
callback->Cancel();
else
callback->Continue(config_.selected_accept_filter,
config_.callback_paths);
callback->Continue(config_.callback_paths);
}
// CefDialogHandler
@ -101,7 +93,6 @@ class DialogTestHandler : public TestHandler {
const CefString& title,
const CefString& default_file_name,
const std::vector<CefString>& accept_types,
int selected_accept_filter,
CefRefPtr<CefFileDialogCallback> callback) override {
got_onfiledialog_.yes();
@ -155,21 +146,6 @@ TEST(DialogTest, FileEmptyParams) {
ReleaseAndWaitForDestructor(handler);
}
TEST(DialogTest, FileAdditionalFlags) {
DialogTestHandler::TestConfig config(static_cast<cef_file_dialog_mode_t>(
FILE_DIALOG_OPEN | FILE_DIALOG_HIDEREADONLY_FLAG |
FILE_DIALOG_OVERWRITEPROMPT_FLAG));
config.title.clear();
config.default_file_name.clear();
config.accept_types.clear();
config.callback_async = false;
config.callback_cancel = false;
CefRefPtr<DialogTestHandler> handler = new DialogTestHandler(config);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
}
TEST(DialogTest, FileOpen) {
DialogTestHandler::TestConfig config(FILE_DIALOG_OPEN);
config.callback_async = false;

View File

@ -50,6 +50,7 @@ const char kShowChromeToolbar[] = "show-chrome-toolbar";
const char kInitialShowState[] = "initial-show-state";
const char kHideChromeStatusBubble[] = "hide-chrome-status-bubble";
const char kUseDefaultPopup[] = "use-default-popup";
const char kUseClientDialogs[] = "use-client-dialogs";
} // namespace switches
} // namespace client

View File

@ -44,6 +44,7 @@ extern const char kShowChromeToolbar[];
extern const char kInitialShowState[];
extern const char kHideChromeStatusBubble[];
extern const char kUseDefaultPopup[];
extern const char kUseClientDialogs[];
} // namespace switches
} // namespace client