diff --git chrome/browser/file_select_helper.cc chrome/browser/file_select_helper.cc index 5d563a5311ec1..7c8c70393ed4b 100644 --- chrome/browser/file_select_helper.cc +++ chrome/browser/file_select_helper.cc @@ -313,6 +313,12 @@ void FileSelectHelper::OnListDone(int error) { } if (dialog_type_ == ui::SelectFileDialog::SELECT_UPLOAD_FOLDER) { + if (run_from_cef_) { + // Don't show the upload confirmation dialog when triggered via CEF + // (initially or recursively). + PerformContentAnalysisIfNeeded(std::move(chooser_files)); + return; + } auto model = CreateConfirmationDialog( entry->display_name_, std::move(chooser_files), base::BindOnce(&FileSelectHelper::PerformContentAnalysisIfNeeded, @@ -511,31 +517,51 @@ FileSelectHelper::GetFileTypesFromAcceptType( std::vector* extensions = &file_type->extensions.back(); + // Create individual filters for each accept type. + std::vector> all_extensions; + std::vector all_overrides; + std::vector all_mimetypes; + // Find the corresponding extensions. int valid_type_count = 0; int description_id = 0; + std::string ascii_type; for (const auto& accept_type : accept_types) { + std::vector current_extensions; + description_id = 0; + ascii_type.clear(); + 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; - std::string ascii_type = base::UTF16ToASCII(accept_type); + ascii_type = base::UTF16ToASCII(accept_type); if (ascii_type == "image/*") description_id = IDS_IMAGE_FILES; else if (ascii_type == "audio/*") 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()); + all_mimetypes.push_back(ascii_type.empty() ? + std::u16string() : accept_type); + + extensions->insert(extensions->end(), current_extensions.begin(), + current_extensions.end()); + } if (extensions->size() > old_extension_size) valid_type_count++; } @@ -552,12 +578,28 @@ FileSelectHelper::GetFileTypesFromAcceptType( // dialog uses the first extension in the list to form the description, // like "EHTML Files". This is not what we want. if (valid_type_count > 1 || - (valid_type_count == 1 && description_id == 0 && extensions->size() > 1)) + (valid_type_count == 1 && description_id == 0 && extensions->size() > 1)) { description_id = IDS_CUSTOM_FILES; + ascii_type.clear(); + } - if (description_id) { - file_type->extension_description_overrides.push_back( - l10n_util::GetStringUTF16(description_id)); + file_type->extension_description_overrides.push_back( + description_id != 0 ? + l10n_util::GetStringUTF16(description_id) : + std::u16string()); + file_type->extension_mimetypes.push_back( + ascii_type.empty() ? std::u16string() : base::ASCIIToUTF16(ascii_type)); + + if (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()); + file_type->extension_mimetypes.insert( + file_type->extension_mimetypes.begin(), + all_mimetypes.begin(), all_mimetypes.end()); } return file_type; @@ -567,7 +609,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()); @@ -575,6 +618,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()); } diff --git chrome/browser/file_select_helper.h chrome/browser/file_select_helper.h index 921b36076c3f3..d61248be1997b 100644 --- chrome/browser/file_select_helper.h +++ chrome/browser/file_select_helper.h @@ -64,7 +64,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( @@ -336,6 +337,9 @@ class FileSelectHelper : public base::RefCountedThreadSafe< scoped_disallow_picture_in_picture_; #endif // !BUILDFLAG(IS_ANDROID) + // Set to true if this dialog was triggered via CEF. + bool run_from_cef_ = false; + #if BUILDFLAG(IS_CHROMEOS_ASH) base::WeakPtrFactory weak_ptr_factory_{this}; #endif // BUILDFLAG(IS_CHROMEOS_ASH) diff --git chrome/browser/ui/chrome_select_file_policy.h chrome/browser/ui/chrome_select_file_policy.h index 49272553c7c53..5ba90c9a06ecf 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 ui/shell_dialogs/select_file_dialog.cc ui/shell_dialogs/select_file_dialog.cc index f9c0d03193a63..f32f02d216120 100644 --- ui/shell_dialogs/select_file_dialog.cc +++ ui/shell_dialogs/select_file_dialog.cc @@ -88,8 +88,10 @@ void SelectFileDialog::SetFactory( // 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 eb3d997598631..e3002e471e842 100644 --- ui/shell_dialogs/select_file_dialog.h +++ ui/shell_dialogs/select_file_dialog.h @@ -96,7 +96,8 @@ class SHELL_DIALOGS_EXPORT SelectFileDialog // listener when there are no calls to SelectFile() outstanding. 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; @@ -130,6 +131,10 @@ class SHELL_DIALOGS_EXPORT SelectFileDialog // FileTypeExtensions instead of this and the above vector? std::vector extension_description_overrides; + // Original mime types for the specified extensions. Entries correspond to + // |extensions|; if left blank then there was no mime type. + std::vector extension_mimetypes; + // Specifies whether there will be a filter added for all files (i.e. *.*). bool include_all_files = false; @@ -224,6 +229,19 @@ class SHELL_DIALOGS_EXPORT SelectFileDialog const GURL* caller = nullptr); 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; @@ -248,6 +266,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 @@ -260,8 +283,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 c7acd9b05fbb8..3e95e4125fa24 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 416c1bb5503ef..a6705c94c0dc2 100644 --- ui/shell_dialogs/select_file_dialog_mac.mm +++ ui/shell_dialogs/select_file_dialog_mac.mm @@ -104,6 +104,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 e3bd03f336edd..afc421d99112f 100644 --- ui/shell_dialogs/select_file_dialog_win.cc +++ ui/shell_dialogs/select_file_dialog_win.cc @@ -251,6 +251,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);