diff --git a/BUILD.gn b/BUILD.gn index 7b0e2c53c..f9347d85c 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -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", diff --git a/include/capi/cef_browser_capi.h b/include/capi/cef_browser_capi.h index 02f76452f..26bac9f5d 100644 --- a/include/capi/cef_browser_capi.h +++ b/include/capi/cef_browser_capi.h @@ -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); /// diff --git a/include/capi/cef_dialog_handler_capi.h b/include/capi/cef_dialog_handler_capi.h index 51563dbdc..c28710ee1 100644 --- a/include/capi/cef_dialog_handler_capi.h +++ b/include/capi/cef_dialog_handler_capi.h @@ -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; diff --git a/include/cef_api_hash.h b/include/cef_api_hash.h index 8dd257fc7..35b1a4310 100644 --- a/include/cef_api_hash.h +++ b/include/cef_api_hash.h @@ -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 diff --git a/include/cef_browser.h b/include/cef_browser.h index a05961a9d..6e1838aec 100644 --- a/include/cef_browser.h +++ b/include/cef_browser.h @@ -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& 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& accept_filters, - int selected_accept_filter, CefRefPtr callback) = 0; /// diff --git a/include/cef_dialog_handler.h b/include/cef_dialog_handler.h index 3ce02e6c1..09059000b 100644 --- a/include/cef_dialog_handler.h +++ b/include/cef_dialog_handler.h @@ -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& file_paths) = 0; + /*--cef(capi_name=cont,optional_param=file_paths)--*/ + virtual void Continue(const std::vector& 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 browser, FileDialogMode mode, const CefString& title, const CefString& default_file_path, const std::vector& accept_filters, - int selected_accept_filter, CefRefPtr callback) { return false; } diff --git a/include/internal/cef_types.h b/include/internal/cef_types.h index 6761698ea..d4dd556f4 100644 --- a/include/internal/cef_types.h +++ b/include/internal/cef_types.h @@ -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; /// diff --git a/libcef/browser/alloy/alloy_browser_host_impl.cc b/libcef/browser/alloy/alloy_browser_host_impl.cc index 8c306191c..9b8f76d55 100644 --- a/libcef/browser/alloy/alloy_browser_host_impl.cc +++ b/libcef/browser/alloy/alloy_browser_host_impl.cc @@ -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& accept_filters, - int selected_accept_filter, - CefRefPtr 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 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())); - } -} diff --git a/libcef/browser/alloy/alloy_browser_host_impl.h b/libcef/browser/alloy/alloy_browser_host_impl.h index d7ff49954..ae25cd990 100644 --- a/libcef/browser/alloy/alloy_browser_host_impl.h +++ b/libcef/browser/alloy/alloy_browser_host_impl.h @@ -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& accept_filters, - int selected_accept_filter, - CefRefPtr 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 file_dialog_manager_; - // Used for creating and managing JavaScript dialogs. std::unique_ptr javascript_dialog_manager_; diff --git a/libcef/browser/alloy/alloy_browser_main.cc b/libcef/browser/alloy/alloy_browser_main.cc index 7c933e610..c481472cb 100644 --- a/libcef/browser/alloy/alloy_browser_main.cc +++ b/libcef/browser/alloy/alloy_browser_main.cc @@ -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 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(); #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) diff --git a/libcef/browser/alloy/alloy_browser_main.h b/libcef/browser/alloy/alloy_browser_main.h index 130fa92c7..cce280241 100644 --- a/libcef/browser/alloy/alloy_browser_main.h +++ b/libcef/browser/alloy/alloy_browser_main.h @@ -42,7 +42,6 @@ class AlloyBrowserMainParts : public content::BrowserMainParts { ~AlloyBrowserMainParts() override; - int PreEarlyInitialization() override; void ToolkitInitialized() override; void PreCreateMainMessageLoop() override; void PostCreateMainMessageLoop() override; diff --git a/libcef/browser/alloy/alloy_content_browser_client.cc b/libcef/browser/alloy/alloy_content_browser_client.cc index 5cc616d20..c42ec6ba7 100644 --- a/libcef/browser/alloy/alloy_content_browser_client.cc +++ b/libcef/browser/alloy/alloy_content_browser_client.cc @@ -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 +AlloyContentBrowserClient::CreateSelectFilePolicy( + content::WebContents* web_contents) { + return std::make_unique(web_contents); +} + void AlloyContentBrowserClient::GetAdditionalAllowedSchemesForFileSystem( std::vector* additional_allowed_schemes) { ContentBrowserClient::GetAdditionalAllowedSchemesForFileSystem( diff --git a/libcef/browser/alloy/alloy_content_browser_client.h b/libcef/browser/alloy/alloy_content_browser_client.h index bcb254655..0e6437d6f 100644 --- a/libcef/browser/alloy/alloy_content_browser_client.h +++ b/libcef/browser/alloy/alloy_content_browser_client.h @@ -58,6 +58,8 @@ class AlloyContentBrowserClient : public content::ContentBrowserClient { std::vector* additional_schemes) override; void GetAdditionalViewSourceSchemes( std::vector* additional_schemes) override; + std::unique_ptr CreateSelectFilePolicy( + content::WebContents* web_contents) override; void GetAdditionalAllowedSchemesForFileSystem( std::vector* additional_allowed_schemes) override; bool IsWebUIAllowedToMakeNetworkRequests(const url::Origin& origin) override; diff --git a/libcef/browser/alloy/alloy_dialog_util.cc b/libcef/browser/alloy/alloy_dialog_util.cc deleted file mode 100644 index ca6d0d3fc..000000000 --- a/libcef/browser/alloy/alloy_dialog_util.cc +++ /dev/null @@ -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 browser = static_cast( - 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 diff --git a/libcef/browser/alloy/alloy_dialog_util.h b/libcef/browser/alloy/alloy_dialog_util.h deleted file mode 100644 index 956cc58df..000000000 --- a/libcef/browser/alloy/alloy_dialog_util.h +++ /dev/null @@ -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 -#include - -#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& /*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_ diff --git a/libcef/browser/alloy/chrome_profile_alloy.cc b/libcef/browser/alloy/chrome_profile_alloy.cc index 644c47e0c..58f5cc3ab 100644 --- a/libcef/browser/alloy/chrome_profile_alloy.cc +++ b/libcef/browser/alloy/chrome_profile_alloy.cc @@ -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() { diff --git a/libcef/browser/alloy/chrome_profile_alloy.h b/libcef/browser/alloy/chrome_profile_alloy.h index d4fdf462f..95c6ca914 100644 --- a/libcef/browser/alloy/chrome_profile_alloy.h +++ b/libcef/browser/alloy/chrome_profile_alloy.h @@ -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_client_; + base::FilePath last_selected_directory_; }; #endif // CEF_LIBCEF_BROWSER_ALLOY_CHROME_PROFILE_ALLOY_H_ diff --git a/libcef/browser/browser_host_base.cc b/libcef/browser/browser_host_base.cc index 2510a67e6..bbb782f79 100644 --- a/libcef/browser/browser_host_base.cc +++ b/libcef/browser/browser_host_base.cc @@ -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& accept_filters, + CefRefPtr 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 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 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( + 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(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(this); + } + return true; +} diff --git a/libcef/browser/browser_host_base.h b/libcef/browser/browser_host_base.h index 3aa5821c2..016bfb040 100644 --- a/libcef/browser/browser_host_base.h +++ b/libcef/browser/browser_host_base.h @@ -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 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& accept_filters, + CefRefPtr 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 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 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 client_; @@ -301,6 +340,9 @@ class CefBrowserHostBase : public CefBrowserHost, // Only accessed on the UI thread. base::ObserverList observers_; + // Used for creating and managing file dialogs. + std::unique_ptr file_dialog_manager_; + // Volatile state accessed from multiple threads. All access must be protected // by |state_lock_|. base::Lock state_lock_; diff --git a/libcef/browser/browser_platform_delegate.cc b/libcef/browser/browser_platform_delegate.cc index 6338312c6..103117636 100644 --- a/libcef/browser/browser_platform_delegate.cc +++ b/libcef/browser/browser_platform_delegate.cc @@ -223,12 +223,6 @@ CefEventHandle CefBrowserPlatformDelegate::GetEventHandle( return kNullEventHandle; } -std::unique_ptr -CefBrowserPlatformDelegate::CreateFileDialogRunner() { - NOTIMPLEMENTED(); - return nullptr; -} - std::unique_ptr CefBrowserPlatformDelegate::CreateJavaScriptDialogRunner() { NOTIMPLEMENTED(); diff --git a/libcef/browser/browser_platform_delegate.h b/libcef/browser/browser_platform_delegate.h index a72707987..6ff01e656 100644 --- a/libcef/browser/browser_platform_delegate.h +++ b/libcef/browser/browser_platform_delegate.h @@ -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 CreateFileDialogRunner(); - // Create the platform-specific JavaScript dialog runner. virtual std::unique_ptr CreateJavaScriptDialogRunner(); diff --git a/libcef/browser/chrome/chrome_browser_host_impl.cc b/libcef/browser/chrome/chrome_browser_host_impl.cc index 4e5607083..05d26de63 100644 --- a/libcef/browser/chrome/chrome_browser_host_impl.cc +++ b/libcef/browser/chrome/chrome_browser_host_impl.cc @@ -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& accept_filters, - int selected_accept_filter, - CefRefPtr callback) { - NOTIMPLEMENTED(); - callback->OnFileDialogDismissed(0, {}); -} - void ChromeBrowserHostImpl::Print() { if (!CEF_CURRENTLY_ON_UIT()) { CEF_POST_TASK(CEF_UIT, base::BindOnce(&ChromeBrowserHostImpl::Print, this)); diff --git a/libcef/browser/chrome/chrome_browser_host_impl.h b/libcef/browser/chrome/chrome_browser_host_impl.h index 00c1576af..faabce1a4 100644 --- a/libcef/browser/chrome/chrome_browser_host_impl.h +++ b/libcef/browser/chrome/chrome_browser_host_impl.h @@ -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& accept_filters, - int selected_accept_filter, - CefRefPtr callback) override; void Print() override; void PrintToPDF(const CefString& path, const CefPdfPrintSettings& settings, diff --git a/libcef/browser/chrome/chrome_browser_main_extra_parts_cef.cc b/libcef/browser/chrome/chrome_browser_main_extra_parts_cef.cc index 34450621c..8fc6e206c 100644 --- a/libcef/browser/chrome/chrome_browser_main_extra_parts_cef.cc +++ b/libcef/browser/chrome/chrome_browser_main_extra_parts_cef.cc @@ -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(); } diff --git a/libcef/browser/devtools/devtools_file_manager.cc b/libcef/browser/devtools/devtools_file_manager.cc index 36981c5a6..54139a2b7 100644 --- a/libcef/browser/devtools/devtools_file_manager.cc +++ b/libcef/browser/devtools/devtools_file_manager.cc @@ -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& file_paths) { if (file_paths.size() == 1) { SaveAsFileSelected(url, content, std::move(saveCallback), file_paths[0]); diff --git a/libcef/browser/devtools/devtools_file_manager.h b/libcef/browser/devtools/devtools_file_manager.h index c15d5d190..27c506fb7 100644 --- a/libcef/browser/devtools/devtools_file_manager.h +++ b/libcef/browser/devtools/devtools_file_manager.h @@ -49,7 +49,6 @@ class CefDevToolsFileManager { const std::string& content, SaveCallback saveCallback, CancelCallback cancelCallback, - int selected_accept_filter, const std::vector& file_paths); void SaveAsFileSelected(const std::string& url, const std::string& content, diff --git a/libcef/browser/download_manager_delegate.cc b/libcef/browser/download_manager_delegate.cc index ed89976fd..60942a91c 100644 --- a/libcef/browser/download_manager_delegate.cc +++ b/libcef/browser/download_manager_delegate.cc @@ -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& file_paths) { DCHECK_LE(file_paths.size(), (size_t)1); diff --git a/libcef/browser/extensions/api/file_system/cef_file_system_delegate.cc b/libcef/browser/extensions/api/file_system/cef_file_system_delegate.cc index f3283f85b..5941c7438 100644 --- a/libcef/browser/extensions/api/file_system/cef_file_system_delegate.cc +++ b/libcef/browser/extensions/api/file_system/cef_file_system_delegate.cc @@ -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 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& 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, diff --git a/libcef/browser/extensions/api/file_system/cef_file_system_delegate.h b/libcef/browser/extensions/api/file_system/cef_file_system_delegate.h index 1d469ff70..910c6e106 100644 --- a/libcef/browser/extensions/api/file_system/cef_file_system_delegate.h +++ b/libcef/browser/extensions/api/file_system/cef_file_system_delegate.h @@ -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& file_paths); - - base::WeakPtrFactory weak_ptr_factory_{this}; }; } // namespace cef diff --git a/libcef/browser/extensions/browser_platform_delegate_background.cc b/libcef/browser/extensions/browser_platform_delegate_background.cc index 0d0042b50..57e301972 100644 --- a/libcef/browser/extensions/browser_platform_delegate_background.cc +++ b/libcef/browser/extensions/browser_platform_delegate_background.cc @@ -102,11 +102,6 @@ CefEventHandle CefBrowserPlatformDelegateBackground::GetEventHandle( return native_delegate_->GetEventHandle(event); } -std::unique_ptr -CefBrowserPlatformDelegateBackground::CreateFileDialogRunner() { - return native_delegate_->CreateFileDialogRunner(); -} - std::unique_ptr CefBrowserPlatformDelegateBackground::CreateJavaScriptDialogRunner() { return native_delegate_->CreateJavaScriptDialogRunner(); diff --git a/libcef/browser/extensions/browser_platform_delegate_background.h b/libcef/browser/extensions/browser_platform_delegate_background.h index 6793893e5..608b16141 100644 --- a/libcef/browser/extensions/browser_platform_delegate_background.h +++ b/libcef/browser/extensions/browser_platform_delegate_background.h @@ -40,7 +40,6 @@ class CefBrowserPlatformDelegateBackground const content::NativeWebKeyboardEvent& event) override; CefEventHandle GetEventHandle( const content::NativeWebKeyboardEvent& event) const override; - std::unique_ptr CreateFileDialogRunner() override; std::unique_ptr CreateJavaScriptDialogRunner() override; std::unique_ptr CreateMenuRunner() override; diff --git a/libcef/browser/file_dialog_manager.cc b/libcef/browser/file_dialog_manager.cc index f1f56d3d5..ceaee4994 100644 --- a/libcef/browser/file_dialog_manager.cc +++ b/libcef/browser/file_dialog_manager.cc @@ -8,18 +8,22 @@ #include #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& file_paths) override { + void Continue(const std::vector& file_paths) override { if (CEF_CURRENTLY_ON_UIT()) { if (!callback_.is_null()) { std::vector 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 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 callback, - int selected_accept_filter, const std::vector& file_paths) { std::vector 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 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 file_paths; - std::move(callback).Run(0, file_paths); + ~CefFileSelectListener() override = default; + + void FileSelected(std::vector files, + const base::FilePath& base_dir, + FileChooserParams::Mode mode) override { + std::vector 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 select_files_; + void FileSelectionCanceled() override { std::move(callback_).Run({}); } + + CallbackType callback_; }; } // namespace -CefFileDialogManager::CefFileDialogManager( - AlloyBrowserHostImpl* browser, - std::unique_ptr 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& files, + void* params) override { + DCHECK_EQ(params, params_); + executing_ = true; + listener_->MultiFilesSelected(files, params); + Destroy(); + } + + void MultiFilesSelectedWithExtraInfo( + const std::vector& 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& accept_filters, - int selected_accept_filter, CefRefPtr 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 listener, - const blink::mojom::FileChooserParams& params) { + const blink::mojom::FileChooserParams& params, + RunFileChooserCallback callback) { CEF_REQUIRE_UIT(); - CefFileDialogRunner::FileChooserParams cef_params; - static_cast(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()); + // 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 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(std::move(callback)), + new_params, /*run_from_cef=*/true); +} + +void CefFileDialogManager::RunSelectFile( + ui::SelectFileDialog::Listener* listener, + std::unique_ptr 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::const_iterator it; std::vector accept_filters; @@ -284,10 +498,9 @@ void CefFileDialogManager::RunFileChooserInternal( CefRefPtr callbackImpl( new CefFileDialogCallbackImpl(std::move(callback))); - handled = handler->OnFileDialog( + const bool handled = handler->OnFileDialog( browser_, static_cast(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()); - } - } + return callback; } -void CefFileDialogManager::OnRunFileChooserCallback( - CefFileDialogRunner::RunFileChooserCallback callback, - int selected_accept_filter, - const std::vector& file_paths) { +void CefFileDialogManager::SelectFileDoneByDelegateCallback( + ui::SelectFileDialog::Listener* listener, + void* params, + const std::vector& 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 listener, - int selected_accept_filter, - const std::vector& 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 listener, - int selected_accept_filter, - const std::vector& file_paths) { +void CefFileDialogManager::SelectFileDoneByListenerCallback( + bool listener_destroyed) { CEF_REQUIRE_UIT(); - base::FilePath base_dir; - std::vector 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; } diff --git a/libcef/browser/file_dialog_manager.h b/libcef/browser/file_dialog_manager.h index cc493268d..dba19fc6e 100644 --- a/libcef/browser/file_dialog_manager.h +++ b/libcef/browser/file_dialog_manager.h @@ -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 +#include -#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 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& accept_filters, - int selected_accept_filter, CefRefPtr callback); - // Called from AlloyBrowserHostImpl::RunFileChooser. - // See WebContentsDelegate::RunFileChooser documentation. - void RunFileChooser(scoped_refptr listener, - const blink::mojom::FileChooserParams& params); + // The argument vector will be empty if the dialog was canceled. + using RunFileChooserCallback = + base::OnceCallback&)>; - // 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 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& file_paths); + void SelectFileDoneByDelegateCallback( + ui::SelectFileDialog::Listener* listener, + void* params, + const std::vector& 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 listener, - int selected_accept_filter, - const std::vector& 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 listener, - int selected_accept_filter, - const std::vector& file_paths); + // Used when running a platform dialog via RunSelectFile. + scoped_refptr dialog_; + CefSelectFileDialogListener* dialog_listener_ = nullptr; - // Clean up state associated with the last run. - void Cleanup(); + // List of all currently active listeners. + std::set active_listeners_; - // AlloyBrowserHostImpl pointer is guaranteed to outlive this object. - AlloyBrowserHostImpl* browser_; - - std::unique_ptr runner_; - - // True if a file chooser is currently pending. - bool file_chooser_pending_; - - // Used for asynchronously listing directory contents. - std::unique_ptr lister_; - - // Must be the last member. - base::WeakPtrFactory weak_ptr_factory_; + base::WeakPtrFactory weak_ptr_factory_{this}; }; #endif // CEF_LIBCEF_BROWSER_JAVASCRIPT_DIALOG_MANAGER_H_ diff --git a/libcef/browser/file_dialog_runner.cc b/libcef/browser/file_dialog_runner.cc new file mode 100644 index 000000000..effc1cd35 --- /dev/null +++ b/libcef/browser/file_dialog_runner.cc @@ -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>::get(); + } + + ui::SelectFileDialog* Create( + ui::SelectFileDialog::Listener* listener, + std::unique_ptr policy) override; + + bool IsCefFactory() const override { return true; } + + private: + friend struct base::DefaultSingletonTraits; + + CefSelectFileDialogFactory() { ui::SelectFileDialog::SetFactory(this); } +}; + +CefRefPtr 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 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 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(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 browser_; +}; + +ui::SelectFileDialog* CefSelectFileDialogFactory::Create( + ui::SelectFileDialog::Listener* listener, + std::unique_ptr 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 diff --git a/libcef/browser/file_dialog_runner.h b/libcef/browser/file_dialog_runner.h index 6c9ad2ccd..679a2c6ae 100644 --- a/libcef/browser/file_dialog_runner.h +++ b/libcef/browser/file_dialog_runner.h @@ -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 +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&)>; - - // 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() = default; - virtual ~CefFileDialogRunner() = default; -}; +} // namespace file_dialog_runner #endif // CEF_LIBCEF_BROWSER_FILE_DIALOG_RUNNER_H_ diff --git a/libcef/browser/native/browser_platform_delegate_native_mac.h b/libcef/browser/native/browser_platform_delegate_native_mac.h index b12f461a9..a1a1bef17 100644 --- a/libcef/browser/native/browser_platform_delegate_native_mac.h +++ b/libcef/browser/native/browser_platform_delegate_native_mac.h @@ -40,7 +40,6 @@ class CefBrowserPlatformDelegateNativeMac const content::NativeWebKeyboardEvent& event) override; CefEventHandle GetEventHandle( const content::NativeWebKeyboardEvent& event) const override; - std::unique_ptr CreateFileDialogRunner() override; std::unique_ptr CreateJavaScriptDialogRunner() override; std::unique_ptr CreateMenuRunner() override; diff --git a/libcef/browser/native/browser_platform_delegate_native_mac.mm b/libcef/browser/native/browser_platform_delegate_native_mac.mm index b2f472b0a..48f13aa41 100644 --- a/libcef/browser/native/browser_platform_delegate_native_mac.mm +++ b/libcef/browser/native/browser_platform_delegate_native_mac.mm @@ -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 -CefBrowserPlatformDelegateNativeMac::CreateFileDialogRunner() { - return base::WrapUnique(new CefFileDialogRunnerMac); -} - std::unique_ptr CefBrowserPlatformDelegateNativeMac::CreateJavaScriptDialogRunner() { return base::WrapUnique(new CefJavaScriptDialogRunnerMac); diff --git a/libcef/browser/native/browser_platform_delegate_native_win.cc b/libcef/browser/native/browser_platform_delegate_native_win.cc index 5483de40d..9e8ffeb5f 100644 --- a/libcef/browser/native/browser_platform_delegate_native_win.cc +++ b/libcef/browser/native/browser_platform_delegate_native_win.cc @@ -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(&event.os_event->native_event())); } -std::unique_ptr -CefBrowserPlatformDelegateNativeWin::CreateFileDialogRunner() { - return base::WrapUnique(new CefFileDialogRunnerWin); -} - std::unique_ptr CefBrowserPlatformDelegateNativeWin::CreateJavaScriptDialogRunner() { return base::WrapUnique(new CefJavaScriptDialogRunnerWin); diff --git a/libcef/browser/native/browser_platform_delegate_native_win.h b/libcef/browser/native/browser_platform_delegate_native_win.h index 58689a04c..2fbefab72 100644 --- a/libcef/browser/native/browser_platform_delegate_native_win.h +++ b/libcef/browser/native/browser_platform_delegate_native_win.h @@ -34,7 +34,6 @@ class CefBrowserPlatformDelegateNativeWin const content::NativeWebKeyboardEvent& event) override; CefEventHandle GetEventHandle( const content::NativeWebKeyboardEvent& event) const override; - std::unique_ptr CreateFileDialogRunner() override; std::unique_ptr CreateJavaScriptDialogRunner() override; std::unique_ptr CreateMenuRunner() override; diff --git a/libcef/browser/native/file_dialog_runner_mac.h b/libcef/browser/native/file_dialog_runner_mac.h deleted file mode 100644 index 58c9da60d..000000000 --- a/libcef/browser/native/file_dialog_runner_mac.h +++ /dev/null @@ -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 weak_this, - const CefFileDialogRunner::FileChooserParams& params, - NSView* view, - int filter_index); - static void RunSaveFileDialog( - base::WeakPtr weak_this, - const CefFileDialogRunner::FileChooserParams& params, - NSView* view, - int filter_index); - - CefFileDialogRunner::RunFileChooserCallback callback_; - base::WeakPtrFactory weak_ptr_factory_; -}; - -#endif // CEF_LIBCEF_BROWSER_NATIVE_FILE_DIALOG_RUNNER_MAC_H_ diff --git a/libcef/browser/native/file_dialog_runner_mac.mm b/libcef/browser/native/file_dialog_runner_mac.mm deleted file mode 100644 index 00d15645d..000000000 --- a/libcef/browser/native/file_dialog_runner_mac.mm +++ /dev/null @@ -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 -#import - -#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& accept_filters, - bool include_all_files, - std::vector>* 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 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& 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 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()); - } -} - -} // namespace - -// Used to manage the file type filter in the NSSavePanel/NSOpenPanel. -@interface CefFilterDelegate : NSObject { - @private - NSSavePanel* panel_; - std::vector> extensions_; - int selected_index_; -} -- (id)initWithPanel:(NSSavePanel*)panel - andAcceptFilters:(const std::vector&)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&)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(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(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& 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 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 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()); - } - }]; -} - -// static -void CefFileDialogRunnerMac::RunSaveFileDialog( - base::WeakPtr 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 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()); - } - }]; -} diff --git a/libcef/browser/native/file_dialog_runner_win.cc b/libcef/browser/native/file_dialog_runner_win.cc deleted file mode 100644 index b4b0f39e5..000000000 --- a/libcef/browser/native/file_dialog_runner_win.cc +++ /dev/null @@ -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 - -#include -#include -#include - -#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, ®_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& file_ext, - const std::vector& 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 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& accept_filters) { - std::vector extensions; - std::vector 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& 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 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* 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 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 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::iterator path = files.begin(); - for (std::vector::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 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 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); -} diff --git a/libcef/browser/native/file_dialog_runner_win.h b/libcef/browser/native/file_dialog_runner_win.h deleted file mode 100644 index e05ea6827..000000000 --- a/libcef/browser/native/file_dialog_runner_win.h +++ /dev/null @@ -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_ diff --git a/libcef/browser/osr/browser_platform_delegate_osr.cc b/libcef/browser/osr/browser_platform_delegate_osr.cc index 427533baa..0fd5b4770 100644 --- a/libcef/browser/osr/browser_platform_delegate_osr.cc +++ b/libcef/browser/osr/browser_platform_delegate_osr.cc @@ -194,11 +194,6 @@ CefEventHandle CefBrowserPlatformDelegateOsr::GetEventHandle( return native_delegate_->GetEventHandle(event); } -std::unique_ptr -CefBrowserPlatformDelegateOsr::CreateFileDialogRunner() { - return native_delegate_->CreateFileDialogRunner(); -} - std::unique_ptr CefBrowserPlatformDelegateOsr::CreateJavaScriptDialogRunner() { return native_delegate_->CreateJavaScriptDialogRunner(); diff --git a/libcef/browser/osr/browser_platform_delegate_osr.h b/libcef/browser/osr/browser_platform_delegate_osr.h index 5efb3ee96..a8c08a9da 100644 --- a/libcef/browser/osr/browser_platform_delegate_osr.h +++ b/libcef/browser/osr/browser_platform_delegate_osr.h @@ -49,7 +49,6 @@ class CefBrowserPlatformDelegateOsr const content::NativeWebKeyboardEvent& event) override; CefEventHandle GetEventHandle( const content::NativeWebKeyboardEvent& event) const override; - std::unique_ptr CreateFileDialogRunner() override; std::unique_ptr CreateJavaScriptDialogRunner() override; std::unique_ptr CreateMenuRunner() override; diff --git a/libcef/browser/printing/print_dialog_linux.cc b/libcef/browser/printing/print_dialog_linux.cc index d51cf40e2..e91a2bcd8 100644 --- a/libcef/browser/printing/print_dialog_linux.cc +++ b/libcef/browser/printing/print_dialog_linux.cc @@ -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 GetBrowserForContext( + printing::PrintingContextLinux* context) { + return extensions::GetOwnerBrowserForGlobalId( + frame_util::MakeGlobalId(context->render_process_id(), + context->render_frame_id()), + nullptr); +} + +CefRefPtr GetPrintHandlerForBrowser( + CefRefPtr browser) { + if (browser) { + if (auto client = browser->GetClient()) { + return client->GetPrintHandler(); + } + } + return nullptr; +} + +} // namespace + class CefPrintDialogCallbackImpl : public CefPrintDialogCallback { public: explicit CefPrintDialogCallbackImpl(CefRefPtr 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 browser) { CEF_REQUIRE_UIT(); @@ -146,14 +211,13 @@ void CefPrintDialogLinux::OnPrintStart(CefRefPtr browser) { } } -CefPrintDialogLinux::CefPrintDialogLinux(PrintingContextLinux* context) - : context_(context) { +CefPrintDialogLinux::CefPrintDialogLinux(PrintingContextLinux* context, + CefRefPtr browser, + CefRefPtr 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 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 settings, bool get_defaults) { CEF_REQUIRE_UIT(); - SetHandler(); - if (!handler_.get()) - return false; - CefRefPtr settings_impl( new CefPrintSettingsImpl(std::move(settings), false)); handler_->OnPrintSettings(browser_.get(), settings_impl.get(), get_defaults); diff --git a/libcef/browser/printing/print_dialog_linux.h b/libcef/browser/printing/print_dialog_linux.h index e3b1c377d..c06369509 100644 --- a/libcef/browser/printing/print_dialog_linux.h +++ b/libcef/browser/printing/print_dialog_linux.h @@ -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 browser); @@ -65,12 +72,11 @@ class CefPrintDialogLinux : public printing::PrintDialogGtkInterface, friend class CefPrintDialogCallbackImpl; friend class CefPrintJobCallbackImpl; - explicit CefPrintDialogLinux(PrintingContextLinux* context); + CefPrintDialogLinux(PrintingContextLinux* context, + CefRefPtr browser, + CefRefPtr handler); ~CefPrintDialogLinux() override; - void SetHandler(); - void ReleaseHandler(); - bool UpdateSettings(std::unique_ptr settings, bool get_defaults); @@ -84,12 +90,12 @@ class CefPrintDialogLinux : public printing::PrintDialogGtkInterface, // Handles print job response. void OnJobCompleted(); - CefRefPtr handler_; - // Printing dialog callback. PrintingContextLinux::PrintSettingsCallback callback_; + PrintingContextLinux* context_; CefRefPtr browser_; + CefRefPtr handler_; base::FilePath path_to_pdf_; }; diff --git a/libcef/browser/views/browser_platform_delegate_views.cc b/libcef/browser/views/browser_platform_delegate_views.cc index 82f20cc03..10659232a 100644 --- a/libcef/browser/views/browser_platform_delegate_views.cc +++ b/libcef/browser/views/browser_platform_delegate_views.cc @@ -257,11 +257,6 @@ CefEventHandle CefBrowserPlatformDelegateViews::GetEventHandle( return native_delegate_->GetEventHandle(event); } -std::unique_ptr -CefBrowserPlatformDelegateViews::CreateFileDialogRunner() { - return native_delegate_->CreateFileDialogRunner(); -} - std::unique_ptr CefBrowserPlatformDelegateViews::CreateJavaScriptDialogRunner() { return native_delegate_->CreateJavaScriptDialogRunner(); diff --git a/libcef/browser/views/browser_platform_delegate_views.h b/libcef/browser/views/browser_platform_delegate_views.h index e742a6f50..c18b0cbe9 100644 --- a/libcef/browser/views/browser_platform_delegate_views.h +++ b/libcef/browser/views/browser_platform_delegate_views.h @@ -60,7 +60,6 @@ class CefBrowserPlatformDelegateViews const content::NativeWebKeyboardEvent& event) override; CefEventHandle GetEventHandle( const content::NativeWebKeyboardEvent& event) const override; - std::unique_ptr CreateFileDialogRunner() override; std::unique_ptr CreateJavaScriptDialogRunner() override; std::unique_ptr CreateMenuRunner() override; diff --git a/libcef_dll/cpptoc/browser_host_cpptoc.cc b/libcef_dll/cpptoc/browser_host_cpptoc.cc index c5c89bc1f..7b09a06ee 100644 --- a/libcef_dll/cpptoc/browser_host_cpptoc.cc +++ b/libcef_dll/cpptoc/browser_host_cpptoc.cc @@ -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, diff --git a/libcef_dll/cpptoc/dialog_handler_cpptoc.cc b/libcef_dll/cpptoc/dialog_handler_cpptoc.cc index 6dcffbb17..c1139d12a 100644 --- a/libcef_dll/cpptoc/dialog_handler_cpptoc.cc +++ b/libcef_dll/cpptoc/dialog_handler_cpptoc.cc @@ -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 diff --git a/libcef_dll/cpptoc/file_dialog_callback_cpptoc.cc b/libcef_dll/cpptoc/file_dialog_callback_cpptoc.cc index 7a4bdbcf8..d7f0ccd44 100644 --- a/libcef_dll/cpptoc/file_dialog_callback_cpptoc.cc +++ b/libcef_dll/cpptoc/file_dialog_callback_cpptoc.cc @@ -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 diff --git a/libcef_dll/cpptoc/run_file_dialog_callback_cpptoc.cc b/libcef_dll/cpptoc/run_file_dialog_callback_cpptoc.cc index 33705ecbb..ea8e5e01f 100644 --- a/libcef_dll/cpptoc/run_file_dialog_callback_cpptoc.cc +++ b/libcef_dll/cpptoc/run_file_dialog_callback_cpptoc.cc @@ -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 diff --git a/libcef_dll/ctocpp/browser_host_ctocpp.cc b/libcef_dll/ctocpp/browser_host_ctocpp.cc index a4e10169b..a8868344e 100644 --- a/libcef_dll/ctocpp/browser_host_ctocpp.cc +++ b/libcef_dll/ctocpp/browser_host_ctocpp.cc @@ -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& accept_filters, - int selected_accept_filter, CefRefPtr 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 diff --git a/libcef_dll/ctocpp/browser_host_ctocpp.h b/libcef_dll/ctocpp/browser_host_ctocpp.h index 8cfd9a7f7..ca8f4cbe9 100644 --- a/libcef_dll/ctocpp/browser_host_ctocpp.h +++ b/libcef_dll/ctocpp/browser_host_ctocpp.h @@ -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& accept_filters, - int selected_accept_filter, CefRefPtr callback) override; void StartDownload(const CefString& url) override; void DownloadImage(const CefString& image_url, diff --git a/libcef_dll/ctocpp/dialog_handler_ctocpp.cc b/libcef_dll/ctocpp/dialog_handler_ctocpp.cc index 3377b564c..430f43523 100644 --- a/libcef_dll/ctocpp/dialog_handler_ctocpp.cc +++ b/libcef_dll/ctocpp/dialog_handler_ctocpp.cc @@ -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& accept_filters, - int selected_accept_filter, CefRefPtr 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 diff --git a/libcef_dll/ctocpp/dialog_handler_ctocpp.h b/libcef_dll/ctocpp/dialog_handler_ctocpp.h index f2e0798a1..bcb0b0eaf 100644 --- a/libcef_dll/ctocpp/dialog_handler_ctocpp.h +++ b/libcef_dll/ctocpp/dialog_handler_ctocpp.h @@ -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& accept_filters, - int selected_accept_filter, CefRefPtr callback) override; }; diff --git a/libcef_dll/ctocpp/file_dialog_callback_ctocpp.cc b/libcef_dll/ctocpp/file_dialog_callback_ctocpp.cc index 3b90ba5a3..cddb58dc5 100644 --- a/libcef_dll/ctocpp/file_dialog_callback_ctocpp.cc +++ b/libcef_dll/ctocpp/file_dialog_callback_ctocpp.cc @@ -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& 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) diff --git a/libcef_dll/ctocpp/file_dialog_callback_ctocpp.h b/libcef_dll/ctocpp/file_dialog_callback_ctocpp.h index f18ffeabc..bd76ca7a1 100644 --- a/libcef_dll/ctocpp/file_dialog_callback_ctocpp.h +++ b/libcef_dll/ctocpp/file_dialog_callback_ctocpp.h @@ -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& file_paths) override; + void Continue(const std::vector& file_paths) override; void Cancel() override; }; diff --git a/libcef_dll/ctocpp/run_file_dialog_callback_ctocpp.cc b/libcef_dll/ctocpp/run_file_dialog_callback_ctocpp.cc index fb42b0d4c..6d09c236e 100644 --- a/libcef_dll/ctocpp/run_file_dialog_callback_ctocpp.cc +++ b/libcef_dll/ctocpp/run_file_dialog_callback_ctocpp.cc @@ -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& 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) diff --git a/libcef_dll/ctocpp/run_file_dialog_callback_ctocpp.h b/libcef_dll/ctocpp/run_file_dialog_callback_ctocpp.h index 2b4fc7dde..1681d0344 100644 --- a/libcef_dll/ctocpp/run_file_dialog_callback_ctocpp.h +++ b/libcef_dll/ctocpp/run_file_dialog_callback_ctocpp.h @@ -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& file_paths) override; + void OnFileDialogDismissed(const std::vector& file_paths) override; }; #endif // CEF_LIBCEF_DLL_CTOCPP_RUN_FILE_DIALOG_CALLBACK_CTOCPP_H_ diff --git a/patch/patch.cfg b/patch/patch.cfg index 5f1f0d6ea..32f470782 100644 --- a/patch/patch.cfg +++ b/patch/patch.cfg @@ -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. diff --git a/patch/patches/chrome_browser_browser.patch b/patch/patches/chrome_browser_browser.patch index 9f8bcea50..7bb662e85 100644 --- a/patch/patches/chrome_browser_browser.patch +++ b/patch/patches/chrome_browser_browser.patch @@ -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 diff --git a/patch/patches/chrome_browser_dialogs.patch b/patch/patches/chrome_browser_dialogs.patch new file mode 100644 index 000000000..05394dd80 --- /dev/null +++ b/patch/patches/chrome_browser_dialogs.patch @@ -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 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 + FileSelectHelper::GetFileTypesFromAcceptType( +- const std::vector& accept_types) { ++ const std::vector& accept_types, ++ bool run_from_cef) { + std::unique_ptr base_file_type( + new ui::SelectFileDialog::FileTypeInfo()); + if (accept_types.empty()) +@@ -464,17 +473,24 @@ FileSelectHelper::GetFileTypesFromAcceptType( + std::vector* extensions = + &file_type->extensions.back(); + ++ // Create individual filters for each accept type. ++ std::vector> all_extensions; ++ std::vector all_overrides; ++ + // Find the corresponding extensions. + int valid_type_count = 0; + int description_id = 0; + for (const auto& accept_type : accept_types) { ++ std::vector 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, ¤t_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 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 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 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 +- GetFileTypesFromAcceptType(const std::vector& accept_types); ++ GetFileTypesFromAcceptType(const std::vector& 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 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 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& filter, + int* filter_index, + std::vector* 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* 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& 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::Create( + Listener* listener, +- std::unique_ptr policy) { +- if (dialog_factory_) ++ std::unique_ptr 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 Create( + Listener* listener, +- std::unique_ptr policy); ++ std::unique_ptr 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; + +@@ -229,6 +243,11 @@ class SHELL_DIALOGS_EXPORT SelectFileDialog + // The listener to be notified of selection completion. + raw_ptr listener_; + ++ std::unique_ptr 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 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 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(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 run_state = BeginRun(owner); + diff --git a/patch/patches/chrome_browser_net_export.patch b/patch/patches/chrome_browser_net_export.patch deleted file mode 100644 index 8ad20dc0f..000000000 --- a/patch/patches/chrome_browser_net_export.patch +++ /dev/null @@ -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& file_paths); -+#endif -+ - // Cached pointer to SystemNetworkContextManager's NetExportFileWriter. - raw_ptr 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 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& 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) { diff --git a/patch/patches/print_preview_123.patch b/patch/patches/print_preview_123.patch index 0f219cc18..116ccfdd9 100644 --- a/patch/patches/print_preview_123.patch +++ b/patch/patches/print_preview_123.patch @@ -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() - ->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& 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& 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 diff --git a/tests/cefclient/browser/client_handler.cc b/tests/cefclient/browser/client_handler.cc index e253bddc2..b5915c2c0 100644 --- a/tests/cefclient/browser/client_handler.cc +++ b/tests/cefclient/browser/client_handler.cc @@ -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() { diff --git a/tests/cefclient/browser/dialog_handler_gtk.cc b/tests/cefclient/browser/dialog_handler_gtk.cc index 942e6a469..e31660f10 100644 --- a/tests/cefclient/browser/dialog_handler_gtk.cc +++ b/tests/cefclient/browser/dialog_handler_gtk.cc @@ -136,6 +136,7 @@ GtkWindow* GetWindow(CefRefPtr 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& accept_filters, - int selected_accept_filter, CefRefPtr 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 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(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 filters; AddFilters(GTK_FILE_CHOOSER(dialog), params.accept_filters, true, &filters); - if (params.selected_accept_filter < static_cast(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(); diff --git a/tests/cefclient/browser/dialog_handler_gtk.h b/tests/cefclient/browser/dialog_handler_gtk.h index 4cfb0726c..1ad967155 100644 --- a/tests/cefclient/browser/dialog_handler_gtk.h +++ b/tests/cefclient/browser/dialog_handler_gtk.h @@ -25,7 +25,6 @@ class ClientDialogHandlerGtk : public CefDialogHandler, const CefString& title, const CefString& default_file_path, const std::vector& accept_filters, - int selected_accept_filter, CefRefPtr callback) override; // CefJSDialogHandler methods. @@ -49,10 +48,10 @@ class ClientDialogHandlerGtk : public CefDialogHandler, CefString title; CefString default_file_path; std::vector accept_filters; - int selected_accept_filter; CefRefPtr callback; }; - void OnFileDialogContinue(OnFileDialogParams params, GtkWindow* window); + void OnFileDialogContinue(const OnFileDialogParams& params, + GtkWindow* window); struct OnJSDialogParams { CefRefPtr browser; @@ -62,7 +61,7 @@ class ClientDialogHandlerGtk : public CefDialogHandler, CefString default_prompt_text; CefRefPtr callback; }; - void OnJSDialogContinue(OnJSDialogParams params, GtkWindow* window); + void OnJSDialogContinue(const OnJSDialogParams& params, GtkWindow* window); void GetWindowAndContinue(CefRefPtr browser, base::OnceCallback callback); diff --git a/tests/cefclient/browser/dialog_test.cc b/tests/cefclient/browser/dialog_test.cc index 6e61ab1e4..27a985404 100644 --- a/tests/cefclient/browser/dialog_test.cc +++ b/tests/cefclient/browser/dialog_test.cc @@ -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 { 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& 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( - 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; diff --git a/tests/cefclient/browser/test_runner.cc b/tests/cefclient/browser/test_runner.cc index 304007e35..68665ffad 100644 --- a/tests/cefclient/browser/test_runner.cc +++ b/tests/cefclient/browser/test_runner.cc @@ -312,17 +312,12 @@ void EndTracing(CefRefPtr browser) { // Results in a call to OnFileDialogDismissed. browser_->GetHost()->RunFileDialog( - static_cast(FILE_DIALOG_SAVE | - FILE_DIALOG_OVERWRITEPROMPT_FLAG), - CefString(), // title - path, - std::vector(), // accept_filters - 0, // selected_accept_filter - this); + FILE_DIALOG_SAVE, + /*title=*/CefString(), path, + /*accept_filters=*/std::vector(), this); } void OnFileDialogDismissed( - int selected_accept_filter, const std::vector& file_paths) override { if (!file_paths.empty()) { // File selected. Results in a call to OnEndTracingComplete. @@ -370,17 +365,12 @@ void PrintToPDF(CefRefPtr browser) { accept_filters.push_back(".pdf"); // Results in a call to OnFileDialogDismissed. - browser_->GetHost()->RunFileDialog( - static_cast(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& file_paths) override { if (!file_paths.empty()) { CefPdfPrintSettings settings; diff --git a/tests/cefclient/resources/dialogs.html b/tests/cefclient/resources/dialogs.html index fb1321c33..537011a13 100644 --- a/tests/cefclient/resources/dialogs.html +++ b/tests/cefclient/resources/dialogs.html @@ -65,10 +65,13 @@ Click a button to show the associated dialog type.


-
input type="file": +
input type="file" (.png): +
input type="file" (image/*): +
input type="file" (multiple types):
input type="file" (directory): -
-
+
+
+


diff --git a/tests/ceftests/dialog_unittest.cc b/tests/ceftests/dialog_unittest.cc index 29f004cb1..a629d82ec 100644 --- a/tests/ceftests/dialog_unittest.cc +++ b/tests/ceftests/dialog_unittest.cc @@ -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 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& 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 browser, CefRefPtr 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 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& accept_types, - int selected_accept_filter, CefRefPtr callback) override { got_onfiledialog_.yes(); @@ -155,21 +146,6 @@ TEST(DialogTest, FileEmptyParams) { ReleaseAndWaitForDestructor(handler); } -TEST(DialogTest, FileAdditionalFlags) { - DialogTestHandler::TestConfig config(static_cast( - 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 handler = new DialogTestHandler(config); - handler->ExecuteTest(); - ReleaseAndWaitForDestructor(handler); -} - TEST(DialogTest, FileOpen) { DialogTestHandler::TestConfig config(FILE_DIALOG_OPEN); config.callback_async = false; diff --git a/tests/shared/common/client_switches.cc b/tests/shared/common/client_switches.cc index aaf69ebb3..c56e42779 100644 --- a/tests/shared/common/client_switches.cc +++ b/tests/shared/common/client_switches.cc @@ -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 diff --git a/tests/shared/common/client_switches.h b/tests/shared/common/client_switches.h index cadb9438e..a9c4923bf 100644 --- a/tests/shared/common/client_switches.h +++ b/tests/shared/common/client_switches.h @@ -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