Use Chrome file dialogs on all platforms and runtimes (fixes issue #3314)
All file dialogs irrespective of source, platform and runtime will now be routed through CefFileDialogManager and trigger CefDialogHandler callbacks (see issue #3293). Adds Chrome runtime support for CefBrowserHost::RunFileDialog and CefDialogHandler callbacks. Adds Alloy runtime support for internal GTK file and print dialogs on Linux subject to the following limitations: 1. Internal GTK implementation: - Cannot be used with multi-threaded-message-loop because Chromium's internal GTK implementation is not thread-safe (does not use GDK threads). - Dialogs will not be modal to application windows when used with off-screen rendering due to lack of access to the client's top-level GtkWindow. 2. Cefclient CefDialogHandler implementation: - Cannot be used with Views because it requires a top-level GtkWindow. Due to the above limitations no dialog implementation is currently provided for Views + multi-threaded-message-loop on Linux. In cases where both implementations are supported the cefclient version is now behind an optional `--use-client-dialogs` command-line flag. Expressly forbids multiple simultaneous file dialogs with the internal platform implementation which uses modal dialogs. CefDialogHandler will still be notified and can optionally handle each request without a modal dialog (see issue #3154). Removes some RunFileDialog parameters that are not supported by the Chrome file dialog implementation (selected_accept_filter parameter, cef_file_dialog_mode_t overwrite/read-only flags).
This commit is contained in:
parent
edef01f579
commit
2ea7459a89
9
BUILD.gn
9
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",
|
||||
|
|
|
@ -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);
|
||||
|
||||
///
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -206,14 +206,11 @@ class CefRunFileDialogCallback : public virtual CefBaseRefCounted {
|
|||
public:
|
||||
///
|
||||
// Called asynchronously after the file dialog is dismissed.
|
||||
// |selected_accept_filter| is the 0-based index of the value selected from
|
||||
// the accept filters array passed to CefBrowserHost::RunFileDialog.
|
||||
// |file_paths| will be a single value or a list of values depending on the
|
||||
// dialog mode. If the selection was cancelled |file_paths| will be empty.
|
||||
///
|
||||
/*--cef(index_param=selected_accept_filter,optional_param=file_paths)--*/
|
||||
/*--cef(optional_param=file_paths)--*/
|
||||
virtual void OnFileDialogDismissed(
|
||||
int selected_accept_filter,
|
||||
const std::vector<CefString>& file_paths) = 0;
|
||||
};
|
||||
|
||||
|
@ -421,19 +418,17 @@ class CefBrowserHost : public virtual CefBaseRefCounted {
|
|||
// selectable file types and may any combination of (a) valid lower-cased MIME
|
||||
// types (e.g. "text/*" or "image/*"), (b) individual file extensions (e.g.
|
||||
// ".txt" or ".png"), or (c) combined description and file extension delimited
|
||||
// using "|" and ";" (e.g. "Image Types|.png;.gif;.jpg").
|
||||
// |selected_accept_filter| is the 0-based index of the filter that will be
|
||||
// selected by default. |callback| will be executed after the dialog is
|
||||
// dismissed or immediately if another dialog is already pending. The dialog
|
||||
// will be initiated asynchronously on the UI thread.
|
||||
// using "|" and ";" (e.g. "Image Types|.png;.gif;.jpg"). |callback| will be
|
||||
// executed after the dialog is dismissed or immediately if another dialog is
|
||||
// already pending. The dialog will be initiated asynchronously on the UI
|
||||
// thread.
|
||||
///
|
||||
/*--cef(optional_param=title,optional_param=default_file_path,
|
||||
optional_param=accept_filters,index_param=selected_accept_filter)--*/
|
||||
optional_param=accept_filters)--*/
|
||||
virtual void RunFileDialog(FileDialogMode mode,
|
||||
const CefString& title,
|
||||
const CefString& default_file_path,
|
||||
const std::vector<CefString>& accept_filters,
|
||||
int selected_accept_filter,
|
||||
CefRefPtr<CefRunFileDialogCallback> callback) = 0;
|
||||
|
||||
///
|
||||
|
|
|
@ -48,16 +48,12 @@
|
|||
class CefFileDialogCallback : public virtual CefBaseRefCounted {
|
||||
public:
|
||||
///
|
||||
// Continue the file selection. |selected_accept_filter| should be the 0-based
|
||||
// index of the value selected from the accept filters array passed to
|
||||
// CefDialogHandler::OnFileDialog. |file_paths| should be a single value or a
|
||||
// Continue the file selection. |file_paths| should be a single value or a
|
||||
// list of values depending on the dialog mode. An empty |file_paths| value is
|
||||
// treated the same as calling Cancel().
|
||||
///
|
||||
/*--cef(capi_name=cont,index_param=selected_accept_filter,
|
||||
optional_param=file_paths)--*/
|
||||
virtual void Continue(int selected_accept_filter,
|
||||
const std::vector<CefString>& file_paths) = 0;
|
||||
/*--cef(capi_name=cont,optional_param=file_paths)--*/
|
||||
virtual void Continue(const std::vector<CefString>& file_paths) = 0;
|
||||
|
||||
///
|
||||
// Cancel the file selection.
|
||||
|
@ -85,19 +81,17 @@ class CefDialogHandler : public virtual CefBaseRefCounted {
|
|||
// (a) valid lower-cased MIME types (e.g. "text/*" or "image/*"),
|
||||
// (b) individual file extensions (e.g. ".txt" or ".png"), or (c) combined
|
||||
// description and file extension delimited using "|" and ";" (e.g.
|
||||
// "Image Types|.png;.gif;.jpg"). |selected_accept_filter| is the 0-based
|
||||
// index of the filter that should be selected by default. To display a custom
|
||||
// dialog return true and execute |callback| either inline or at a later time.
|
||||
// To display the default dialog return false.
|
||||
// "Image Types|.png;.gif;.jpg"). To display a custom dialog return true and
|
||||
// execute |callback| either inline or at a later time. To display the default
|
||||
// dialog return false.
|
||||
///
|
||||
/*--cef(optional_param=title,optional_param=default_file_path,
|
||||
optional_param=accept_filters,index_param=selected_accept_filter)--*/
|
||||
optional_param=accept_filters)--*/
|
||||
virtual bool OnFileDialog(CefRefPtr<CefBrowser> browser,
|
||||
FileDialogMode mode,
|
||||
const CefString& title,
|
||||
const CefString& default_file_path,
|
||||
const std::vector<CefString>& accept_filters,
|
||||
int selected_accept_filter,
|
||||
CefRefPtr<CefFileDialogCallback> callback) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
///
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "base/bind.h"
|
||||
#include "base/callback_helpers.h"
|
||||
#include "base/command_line.h"
|
||||
#include "chrome/browser/file_select_helper.h"
|
||||
#include "chrome/browser/picture_in_picture/picture_in_picture_window_manager.h"
|
||||
#include "content/browser/gpu/compositor_util.h"
|
||||
#include "content/public/browser/desktop_media_id.h"
|
||||
|
@ -348,27 +349,6 @@ void AlloyBrowserHostImpl::SetZoomLevel(double zoomLevel) {
|
|||
}
|
||||
}
|
||||
|
||||
void AlloyBrowserHostImpl::RunFileDialog(
|
||||
FileDialogMode mode,
|
||||
const CefString& title,
|
||||
const CefString& default_file_path,
|
||||
const std::vector<CefString>& accept_filters,
|
||||
int selected_accept_filter,
|
||||
CefRefPtr<CefRunFileDialogCallback> callback) {
|
||||
if (!CEF_CURRENTLY_ON_UIT()) {
|
||||
CEF_POST_TASK(CEF_UIT,
|
||||
base::BindOnce(&AlloyBrowserHostImpl::RunFileDialog, this,
|
||||
mode, title, default_file_path, accept_filters,
|
||||
selected_accept_filter, callback));
|
||||
return;
|
||||
}
|
||||
|
||||
EnsureFileDialogManager();
|
||||
file_dialog_manager_->RunFileDialog(mode, title, default_file_path,
|
||||
accept_filters, selected_accept_filter,
|
||||
callback);
|
||||
}
|
||||
|
||||
void AlloyBrowserHostImpl::Print() {
|
||||
if (!CEF_CURRENTLY_ON_UIT()) {
|
||||
CEF_POST_TASK(CEF_UIT, base::BindOnce(&AlloyBrowserHostImpl::Print, this));
|
||||
|
@ -666,8 +646,6 @@ void AlloyBrowserHostImpl::DestroyBrowser() {
|
|||
OnBeforeClose();
|
||||
|
||||
// Destroy any platform constructs first.
|
||||
if (file_dialog_manager_.get())
|
||||
file_dialog_manager_->Destroy();
|
||||
if (javascript_dialog_manager_.get())
|
||||
javascript_dialog_manager_->Destroy();
|
||||
if (menu_manager_.get())
|
||||
|
@ -750,13 +728,6 @@ void AlloyBrowserHostImpl::OnSetFocus(cef_focus_source_t source) {
|
|||
platform_delegate_->SetFocus(true);
|
||||
}
|
||||
|
||||
void AlloyBrowserHostImpl::RunFileChooser(
|
||||
const CefFileDialogRunner::FileChooserParams& params,
|
||||
CefFileDialogRunner::RunFileChooserCallback callback) {
|
||||
EnsureFileDialogManager();
|
||||
file_dialog_manager_->RunFileChooser(params, std::move(callback));
|
||||
}
|
||||
|
||||
void AlloyBrowserHostImpl::EnterFullscreenModeForTab(
|
||||
content::RenderFrameHost* requesting_frame,
|
||||
const blink::mojom::FullscreenOptions& options) {
|
||||
|
@ -1278,8 +1249,9 @@ void AlloyBrowserHostImpl::RunFileChooser(
|
|||
content::RenderFrameHost* render_frame_host,
|
||||
scoped_refptr<content::FileSelectListener> listener,
|
||||
const blink::mojom::FileChooserParams& params) {
|
||||
EnsureFileDialogManager();
|
||||
file_dialog_manager_->RunFileChooser(listener, params);
|
||||
// This will eventually call into CefFileDialogManager.
|
||||
FileSelectHelper::RunFileChooser(render_frame_host, std::move(listener),
|
||||
params);
|
||||
}
|
||||
|
||||
bool AlloyBrowserHostImpl::HandleContextMenu(
|
||||
|
@ -1575,11 +1547,3 @@ void AlloyBrowserHostImpl::UpdateDragCursor(
|
|||
if (platform_delegate_)
|
||||
platform_delegate_->UpdateDragCursor(operation);
|
||||
}
|
||||
|
||||
void AlloyBrowserHostImpl::EnsureFileDialogManager() {
|
||||
CEF_REQUIRE_UIT();
|
||||
if (!file_dialog_manager_.get() && platform_delegate_) {
|
||||
file_dialog_manager_.reset(new CefFileDialogManager(
|
||||
this, platform_delegate_->CreateFileDialogRunner()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
#include "include/cef_frame.h"
|
||||
#include "libcef/browser/browser_host_base.h"
|
||||
#include "libcef/browser/browser_info.h"
|
||||
#include "libcef/browser/file_dialog_manager.h"
|
||||
#include "libcef/browser/frame_host_impl.h"
|
||||
#include "libcef/browser/javascript_dialog_manager.h"
|
||||
#include "libcef/browser/menu_manager.h"
|
||||
|
@ -83,12 +82,6 @@ class AlloyBrowserHostImpl : public CefBrowserHostBase,
|
|||
CefWindowHandle GetOpenerWindowHandle() override;
|
||||
double GetZoomLevel() override;
|
||||
void SetZoomLevel(double zoomLevel) override;
|
||||
void RunFileDialog(FileDialogMode mode,
|
||||
const CefString& title,
|
||||
const CefString& default_file_path,
|
||||
const std::vector<CefString>& accept_filters,
|
||||
int selected_accept_filter,
|
||||
CefRefPtr<CefRunFileDialogCallback> callback) override;
|
||||
void Print() override;
|
||||
void PrintToPDF(const CefString& path,
|
||||
const CefPdfPrintSettings& settings,
|
||||
|
@ -178,12 +171,6 @@ class AlloyBrowserHostImpl : public CefBrowserHostBase,
|
|||
|
||||
void OnSetFocus(cef_focus_source_t source) override;
|
||||
|
||||
// Run the file chooser dialog specified by |params|. Only a single dialog may
|
||||
// be pending at any given time. |callback| will be executed asynchronously
|
||||
// after the dialog is dismissed or if another dialog is already pending.
|
||||
void RunFileChooser(const CefFileDialogRunner::FileChooserParams& params,
|
||||
CefFileDialogRunner::RunFileChooserCallback callback);
|
||||
|
||||
bool HandleContextMenu(content::WebContents* web_contents,
|
||||
const content::ContextMenuParams& params);
|
||||
|
||||
|
@ -329,9 +316,6 @@ class AlloyBrowserHostImpl : public CefBrowserHostBase,
|
|||
// Give the platform delegate an opportunity to create the host window.
|
||||
bool CreateHostWindow();
|
||||
|
||||
// Create the CefFileDialogManager if it doesn't already exist.
|
||||
void EnsureFileDialogManager();
|
||||
|
||||
void StartAudioCapturer();
|
||||
void OnRecentlyAudibleTimerFired();
|
||||
|
||||
|
@ -349,9 +333,6 @@ class AlloyBrowserHostImpl : public CefBrowserHostBase,
|
|||
// on the UI thread.
|
||||
bool window_destroyed_ = false;
|
||||
|
||||
// Used for creating and managing file dialogs.
|
||||
std::unique_ptr<CefFileDialogManager> file_dialog_manager_;
|
||||
|
||||
// Used for creating and managing JavaScript dialogs.
|
||||
std::unique_ptr<CefJavaScriptDialogManager> javascript_dialog_manager_;
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "libcef/browser/context.h"
|
||||
#include "libcef/browser/devtools/devtools_manager_delegate.h"
|
||||
#include "libcef/browser/extensions/extension_system_factory.h"
|
||||
#include "libcef/browser/file_dialog_runner.h"
|
||||
#include "libcef/browser/net/chrome_scheme_handler.h"
|
||||
#include "libcef/browser/printing/constrained_window_views_client.h"
|
||||
#include "libcef/browser/thread_util.h"
|
||||
|
@ -75,11 +76,23 @@
|
|||
|
||||
#if BUILDFLAG(IS_LINUX)
|
||||
#include "base/path_service.h"
|
||||
#include "chrome/browser/themes/theme_service_aura_linux.h"
|
||||
#include "chrome/browser/ui/views/theme_profile_key.h"
|
||||
#include "chrome/common/chrome_paths.h"
|
||||
#include "chrome/grit/chromium_strings.h"
|
||||
#include "components/os_crypt/key_storage_config_linux.h"
|
||||
#include "libcef/browser/printing/print_dialog_linux.h"
|
||||
#include "ui/base/cursor/cursor_factory.h"
|
||||
#include "ui/base/ime/input_method.h"
|
||||
#include "ui/base/ime/linux/fake_input_method_context_factory.h"
|
||||
#include "ui/base/l10n/l10n_util.h"
|
||||
#include "ui/base/linux/linux_ui_delegate.h"
|
||||
#include "ui/ozone/public/ozone_platform.h"
|
||||
#include "ui/views/linux_ui/linux_ui.h"
|
||||
|
||||
#if BUILDFLAG(USE_GTK)
|
||||
#include "ui/gtk/gtk_ui_factory.h"
|
||||
#endif
|
||||
#endif // BUILDFLAG(IS_LINUX)
|
||||
|
||||
#if BUILDFLAG(ENABLE_MEDIA_FOUNDATION_WIDEVINE_CDM)
|
||||
|
@ -90,6 +103,75 @@
|
|||
#include "chrome/browser/component_updater/widevine_cdm_component_installer.h"
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
#if BUILDFLAG(IS_LINUX)
|
||||
|
||||
std::unique_ptr<views::LinuxUI> BuildLinuxUI() {
|
||||
// We can't use GtkUi in combination with multi-threaded-message-loop because
|
||||
// Chromium's GTK implementation doesn't use GDK threads.
|
||||
if (!!CefContext::Get()->settings().multi_threaded_message_loop)
|
||||
return nullptr;
|
||||
|
||||
// If the ozone backend hasn't provided a LinuxUiDelegate, don't try to create
|
||||
// a LinuxUi instance as this may result in a crash in toolkit initialization.
|
||||
if (!ui::LinuxUiDelegate::GetInstance())
|
||||
return nullptr;
|
||||
|
||||
// GtkUi is the only LinuxUI implementation for now.
|
||||
#if BUILDFLAG(USE_GTK)
|
||||
return BuildGtkUi();
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Based on chrome_browser_main_extra_parts_views_linux.cc
|
||||
void ToolkitInitializedLinux() {
|
||||
if (auto linux_ui = BuildLinuxUI()) {
|
||||
linux_ui->SetUseSystemThemeCallback(
|
||||
base::BindRepeating([](aura::Window* window) {
|
||||
if (!window)
|
||||
return true;
|
||||
return ThemeServiceAuraLinux::ShouldUseSystemThemeForProfile(
|
||||
GetThemeProfileForWindow(window));
|
||||
}));
|
||||
|
||||
linux_ui->Initialize();
|
||||
views::LinuxUI::SetInstance(std::move(linux_ui));
|
||||
|
||||
// Cursor theme changes are tracked by LinuxUI (via a CursorThemeManager
|
||||
// implementation). Start observing them once it's initialized.
|
||||
ui::CursorFactory::GetInstance()->ObserveThemeChanges();
|
||||
} else {
|
||||
// In case if GTK is not used, input method factory won't be set for X11 and
|
||||
// Ozone/X11. Set a fake one instead to avoid crashing browser later.
|
||||
DCHECK(!ui::LinuxInputMethodContextFactory::instance());
|
||||
// Try to create input method through Ozone so that the backend has a chance
|
||||
// to set factory by itself.
|
||||
ui::OzonePlatform::GetInstance()->CreateInputMethod(
|
||||
nullptr, gfx::kNullAcceleratedWidget);
|
||||
}
|
||||
// If factory is not set, set a fake instance.
|
||||
if (!ui::LinuxInputMethodContextFactory::instance()) {
|
||||
ui::LinuxInputMethodContextFactory::SetInstance(
|
||||
new ui::FakeInputMethodContextFactory());
|
||||
}
|
||||
|
||||
auto create_print_dialog_func =
|
||||
printing::PrintingContextLinux::SetCreatePrintDialogFunction(
|
||||
&CefPrintDialogLinux::CreatePrintDialog);
|
||||
auto pdf_paper_size_func =
|
||||
printing::PrintingContextLinux::SetPdfPaperSizeFunction(
|
||||
&CefPrintDialogLinux::GetPdfPaperSize);
|
||||
CefPrintDialogLinux::SetDefaultPrintingContextFuncs(create_print_dialog_func,
|
||||
pdf_paper_size_func);
|
||||
}
|
||||
|
||||
#endif // BUILDFLAG(IS_LINUX)
|
||||
|
||||
} // namespace
|
||||
|
||||
AlloyBrowserMainParts::AlloyBrowserMainParts(
|
||||
content::MainFunctionParams parameters)
|
||||
: BrowserMainParts(), parameters_(std::move(parameters)) {}
|
||||
|
@ -98,16 +180,6 @@ AlloyBrowserMainParts::~AlloyBrowserMainParts() {
|
|||
constrained_window::SetConstrainedWindowViewsClient(nullptr);
|
||||
}
|
||||
|
||||
int AlloyBrowserMainParts::PreEarlyInitialization() {
|
||||
#if defined(USE_AURA) && BUILDFLAG(IS_LINUX)
|
||||
// TODO(linux): Consider using a real input method or
|
||||
// views::LinuxUI::SetInstance.
|
||||
ui::InitializeInputMethodForTesting();
|
||||
#endif
|
||||
|
||||
return content::RESULT_CODE_NORMAL_EXIT;
|
||||
}
|
||||
|
||||
void AlloyBrowserMainParts::ToolkitInitialized() {
|
||||
SetConstrainedWindowViewsClient(CreateCefConstrainedWindowViewsClient());
|
||||
#if defined(USE_AURA)
|
||||
|
@ -122,6 +194,10 @@ void AlloyBrowserMainParts::ToolkitInitialized() {
|
|||
#else
|
||||
views_delegate_ = std::make_unique<views::DesktopTestViewsDelegate>();
|
||||
#endif
|
||||
|
||||
#if BUILDFLAG(IS_LINUX)
|
||||
ToolkitInitializedLinux();
|
||||
#endif
|
||||
}
|
||||
|
||||
void AlloyBrowserMainParts::PreCreateMainMessageLoop() {
|
||||
|
@ -148,11 +224,6 @@ void AlloyBrowserMainParts::PreCreateMainMessageLoop() {
|
|||
|
||||
void AlloyBrowserMainParts::PostCreateMainMessageLoop() {
|
||||
#if BUILDFLAG(IS_LINUX)
|
||||
printing::PrintingContextLinux::SetCreatePrintDialogFunction(
|
||||
&CefPrintDialogLinux::CreatePrintDialog);
|
||||
printing::PrintingContextLinux::SetPdfPaperSizeFunction(
|
||||
&CefPrintDialogLinux::GetPdfPaperSize);
|
||||
|
||||
const base::CommandLine* command_line =
|
||||
base::CommandLine::ForCurrentProcess();
|
||||
|
||||
|
@ -241,6 +312,7 @@ int AlloyBrowserMainParts::PreMainMessageLoopRun() {
|
|||
PluginFinder::GetInstance()->Init();
|
||||
|
||||
scheme::RegisterWebUIControllerFactory();
|
||||
file_dialog_runner::RegisterFactory();
|
||||
|
||||
#if BUILDFLAG(ENABLE_MEDIA_FOUNDATION_WIDEVINE_CDM) || \
|
||||
BUILDFLAG(ENABLE_WIDEVINE_CDM_COMPONENT)
|
||||
|
|
|
@ -42,7 +42,6 @@ class AlloyBrowserMainParts : public content::BrowserMainParts {
|
|||
|
||||
~AlloyBrowserMainParts() override;
|
||||
|
||||
int PreEarlyInitialization() override;
|
||||
void ToolkitInitialized() override;
|
||||
void PreCreateMainMessageLoop() override;
|
||||
void PostCreateMainMessageLoop() override;
|
||||
|
|
|
@ -68,6 +68,7 @@
|
|||
#include "chrome/browser/profiles/renderer_updater_factory.h"
|
||||
#include "chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.h"
|
||||
#include "chrome/browser/spellchecker/spell_check_host_chrome_impl.h"
|
||||
#include "chrome/browser/ui/chrome_select_file_policy.h"
|
||||
#include "chrome/common/chrome_content_client.h"
|
||||
#include "chrome/common/chrome_paths.h"
|
||||
#include "chrome/common/chrome_switches.h"
|
||||
|
@ -576,6 +577,12 @@ void AlloyContentBrowserClient::GetAdditionalViewSourceSchemes(
|
|||
additional_schemes->push_back(extensions::kExtensionScheme);
|
||||
}
|
||||
|
||||
std::unique_ptr<ui::SelectFilePolicy>
|
||||
AlloyContentBrowserClient::CreateSelectFilePolicy(
|
||||
content::WebContents* web_contents) {
|
||||
return std::make_unique<ChromeSelectFilePolicy>(web_contents);
|
||||
}
|
||||
|
||||
void AlloyContentBrowserClient::GetAdditionalAllowedSchemesForFileSystem(
|
||||
std::vector<std::string>* additional_allowed_schemes) {
|
||||
ContentBrowserClient::GetAdditionalAllowedSchemesForFileSystem(
|
||||
|
|
|
@ -58,6 +58,8 @@ class AlloyContentBrowserClient : public content::ContentBrowserClient {
|
|||
std::vector<std::string>* additional_schemes) override;
|
||||
void GetAdditionalViewSourceSchemes(
|
||||
std::vector<std::string>* additional_schemes) override;
|
||||
std::unique_ptr<ui::SelectFilePolicy> CreateSelectFilePolicy(
|
||||
content::WebContents* web_contents) override;
|
||||
void GetAdditionalAllowedSchemesForFileSystem(
|
||||
std::vector<std::string>* additional_allowed_schemes) override;
|
||||
bool IsWebUIAllowedToMakeNetworkRequests(const url::Origin& origin) override;
|
||||
|
|
|
@ -1,49 +0,0 @@
|
|||
// Copyright 2021 The Chromium Embedded Framework Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be found
|
||||
// in the LICENSE file.
|
||||
|
||||
#include "libcef/browser/alloy/alloy_dialog_util.h"
|
||||
|
||||
#include "libcef/browser/alloy/alloy_browser_host_impl.h"
|
||||
#include "libcef/browser/extensions/browser_extensions_util.h"
|
||||
#include "libcef/browser/file_dialog_runner.h"
|
||||
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
|
||||
namespace alloy {
|
||||
|
||||
void RunFileChooser(content::WebContents* web_contents,
|
||||
const blink::mojom::FileChooserParams& params,
|
||||
RunFileChooserCallback callback) {
|
||||
CefRefPtr<AlloyBrowserHostImpl> browser = static_cast<AlloyBrowserHostImpl*>(
|
||||
extensions::GetOwnerBrowserForHost(web_contents->GetRenderViewHost(),
|
||||
nullptr)
|
||||
.get());
|
||||
if (!browser) {
|
||||
LOG(ERROR) << "Failed to identify browser; canceling file dialog";
|
||||
std::move(callback).Run(-1, {});
|
||||
return;
|
||||
}
|
||||
|
||||
CefFileDialogRunner::FileChooserParams cef_params;
|
||||
cef_params.mode = params.mode;
|
||||
cef_params.default_file_name = params.default_file_name;
|
||||
cef_params.accept_types = params.accept_types;
|
||||
|
||||
browser->RunFileChooser(cef_params, std::move(callback));
|
||||
}
|
||||
|
||||
// Based on net/base/filename_util_internal.cc FilePathToString16().
|
||||
std::u16string FilePathTypeToString16(const base::FilePath::StringType& str) {
|
||||
std::u16string result;
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
result.assign(str.begin(), str.end());
|
||||
#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
|
||||
if (!str.empty()) {
|
||||
base::UTF8ToUTF16(str.c_str(), str.size(), &result);
|
||||
}
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace alloy
|
|
@ -1,37 +0,0 @@
|
|||
// Copyright 2021 The Chromium Embedded Framework Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be found
|
||||
// in the LICENSE file.
|
||||
|
||||
#ifndef CEF_LIBCEF_BROWSER_ALLOY_ALLOY_DIALOG_UTIL_H_
|
||||
#define CEF_LIBCEF_BROWSER_ALLOY_ALLOY_DIALOG_UTIL_H_
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/callback.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "third_party/blink/public/mojom/choosers/file_chooser.mojom.h"
|
||||
|
||||
namespace content {
|
||||
class WebContents;
|
||||
}
|
||||
|
||||
namespace alloy {
|
||||
|
||||
// The argument vector will be empty if the dialog was canceled.
|
||||
using RunFileChooserCallback =
|
||||
base::OnceCallback<void(int /*selected_accept_filter*/,
|
||||
const std::vector<base::FilePath>& /*file_paths*/)>;
|
||||
|
||||
// Display the file chooser dialog. Execute |callback| on completion.
|
||||
// Called from patched chrome/ files.
|
||||
void RunFileChooser(content::WebContents* web_contents,
|
||||
const blink::mojom::FileChooserParams& params,
|
||||
RunFileChooserCallback callback);
|
||||
|
||||
std::u16string FilePathTypeToString16(const base::FilePath::StringType& str);
|
||||
|
||||
} // namespace alloy
|
||||
|
||||
#endif // CEF_LIBCEF_BROWSER_ALLOY_ALLOY_DIALOG_UTIL_H_
|
|
@ -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() {
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#ifndef CEF_LIBCEF_BROWSER_ALLOY_CHROME_PROFILE_ALLOY_H_
|
||||
#define CEF_LIBCEF_BROWSER_ALLOY_CHROME_PROFILE_ALLOY_H_
|
||||
|
||||
#include "base/files/file_path.h"
|
||||
#include "chrome/browser/profiles/profile.h"
|
||||
|
||||
// This file provides a stub implementation of Chrome's Profile object for use
|
||||
|
@ -54,6 +55,7 @@ class ChromeProfileAlloy : public Profile {
|
|||
|
||||
private:
|
||||
std::unique_ptr<variations::VariationsClient> variations_client_;
|
||||
base::FilePath last_selected_directory_;
|
||||
};
|
||||
|
||||
#endif // CEF_LIBCEF_BROWSER_ALLOY_CHROME_PROFILE_ALLOY_H_
|
||||
|
|
|
@ -20,11 +20,14 @@
|
|||
#include "chrome/browser/spellchecker/spellcheck_service.h"
|
||||
#include "components/favicon/core/favicon_url.h"
|
||||
#include "components/spellcheck/common/spellcheck_features.h"
|
||||
#include "content/browser/renderer_host/render_frame_host_impl.h"
|
||||
#include "content/public/browser/browser_context.h"
|
||||
#include "content/public/browser/download_manager.h"
|
||||
#include "content/public/browser/download_request_utils.h"
|
||||
#include "content/public/browser/file_select_listener.h"
|
||||
#include "content/public/browser/navigation_entry.h"
|
||||
#include "ui/gfx/image/image_skia.h"
|
||||
#include "ui/shell_dialogs/select_file_policy.h"
|
||||
|
||||
#if BUILDFLAG(IS_MAC)
|
||||
#include "components/spellcheck/browser/spellcheck_platform.h"
|
||||
|
@ -208,6 +211,31 @@ void CefBrowserHostBase::SetFocusInternal(bool focus) {
|
|||
platform_delegate_->SetFocus(false);
|
||||
}
|
||||
|
||||
void CefBrowserHostBase::RunFileDialog(
|
||||
FileDialogMode mode,
|
||||
const CefString& title,
|
||||
const CefString& default_file_path,
|
||||
const std::vector<CefString>& accept_filters,
|
||||
CefRefPtr<CefRunFileDialogCallback> callback) {
|
||||
DCHECK(callback);
|
||||
if (!CEF_CURRENTLY_ON_UIT()) {
|
||||
CEF_POST_TASK(CEF_UIT, base::BindOnce(&CefBrowserHostBase::RunFileDialog,
|
||||
this, mode, title, default_file_path,
|
||||
accept_filters, callback));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!callback || !EnsureFileDialogManager()) {
|
||||
LOG(ERROR) << "File dialog canceled due to invalid state.";
|
||||
if (callback)
|
||||
callback->OnFileDialogDismissed({});
|
||||
return;
|
||||
}
|
||||
|
||||
file_dialog_manager_->RunFileDialog(mode, title, default_file_path,
|
||||
accept_filters, callback);
|
||||
}
|
||||
|
||||
void CefBrowserHostBase::StartDownload(const CefString& url) {
|
||||
if (!CEF_CURRENTLY_ON_UIT()) {
|
||||
CEF_POST_TASK(
|
||||
|
@ -805,6 +833,45 @@ void CefBrowserHostBase::ViewText(const std::string& text) {
|
|||
platform_delegate_->ViewText(text);
|
||||
}
|
||||
|
||||
void CefBrowserHostBase::RunFileChooserForBrowser(
|
||||
const blink::mojom::FileChooserParams& params,
|
||||
CefFileDialogManager::RunFileChooserCallback callback) {
|
||||
if (!EnsureFileDialogManager()) {
|
||||
LOG(ERROR) << "File dialog canceled due to invalid state.";
|
||||
std::move(callback).Run({});
|
||||
return;
|
||||
}
|
||||
file_dialog_manager_->RunFileChooser(params, std::move(callback));
|
||||
}
|
||||
|
||||
void CefBrowserHostBase::RunSelectFile(
|
||||
ui::SelectFileDialog::Listener* listener,
|
||||
std::unique_ptr<ui::SelectFilePolicy> policy,
|
||||
ui::SelectFileDialog::Type type,
|
||||
const std::u16string& title,
|
||||
const base::FilePath& default_path,
|
||||
const ui::SelectFileDialog::FileTypeInfo* file_types,
|
||||
int file_type_index,
|
||||
const base::FilePath::StringType& default_extension,
|
||||
gfx::NativeWindow owning_window,
|
||||
void* params) {
|
||||
if (!EnsureFileDialogManager()) {
|
||||
LOG(ERROR) << "File dialog canceled due to invalid state.";
|
||||
listener->FileSelectionCanceled(params);
|
||||
return;
|
||||
}
|
||||
file_dialog_manager_->RunSelectFile(listener, std::move(policy), type, title,
|
||||
default_path, file_types, file_type_index,
|
||||
default_extension, owning_window, params);
|
||||
}
|
||||
|
||||
void CefBrowserHostBase::SelectFileListenerDestroyed(
|
||||
ui::SelectFileDialog::Listener* listener) {
|
||||
if (file_dialog_manager_) {
|
||||
file_dialog_manager_->SelectFileListenerDestroyed(listener);
|
||||
}
|
||||
}
|
||||
|
||||
bool CefBrowserHostBase::MaybeAllowNavigation(
|
||||
content::RenderFrameHost* opener,
|
||||
bool is_guest_view,
|
||||
|
@ -833,6 +900,13 @@ void CefBrowserHostBase::OnBeforeClose() {
|
|||
|
||||
void CefBrowserHostBase::OnBrowserDestroyed() {
|
||||
CEF_REQUIRE_UIT();
|
||||
|
||||
// Destroy any platform constructs.
|
||||
if (file_dialog_manager_) {
|
||||
file_dialog_manager_->Destroy();
|
||||
file_dialog_manager_.reset();
|
||||
}
|
||||
|
||||
for (auto& observer : observers_)
|
||||
observer.OnBrowserDestroyed(this);
|
||||
}
|
||||
|
@ -878,13 +952,36 @@ CefRefPtr<CefBrowserView> CefBrowserHostBase::GetBrowserView() const {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
gfx::NativeWindow CefBrowserHostBase::GetTopLevelNativeWindow() const {
|
||||
CEF_REQUIRE_UIT();
|
||||
// Windowless browsers always return nullptr from GetTopLevelNativeWindow().
|
||||
if (!IsWindowless()) {
|
||||
auto web_contents = GetWebContents();
|
||||
if (web_contents) {
|
||||
return web_contents->GetTopLevelNativeWindow();
|
||||
}
|
||||
}
|
||||
return gfx::NativeWindow();
|
||||
}
|
||||
|
||||
bool CefBrowserHostBase::IsFocused() const {
|
||||
CEF_REQUIRE_UIT();
|
||||
auto web_contents = GetWebContents();
|
||||
if (web_contents) {
|
||||
return static_cast<content::RenderFrameHostImpl*>(
|
||||
web_contents->GetMainFrame())
|
||||
->IsFocused();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CefBrowserHostBase::EnsureDevToolsManager() {
|
||||
CEF_REQUIRE_UIT();
|
||||
if (!contents_delegate_->web_contents())
|
||||
return false;
|
||||
|
||||
if (!devtools_manager_) {
|
||||
devtools_manager_.reset(new CefDevToolsManager(this));
|
||||
devtools_manager_ = std::make_unique<CefDevToolsManager>(this);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -904,3 +1001,14 @@ void CefBrowserHostBase::InitializeDevToolsRegistrationOnUIThread(
|
|||
return;
|
||||
devtools_manager_->InitializeRegistrationOnUIThread(registration);
|
||||
}
|
||||
|
||||
bool CefBrowserHostBase::EnsureFileDialogManager() {
|
||||
CEF_REQUIRE_UIT();
|
||||
if (!contents_delegate_->web_contents())
|
||||
return false;
|
||||
|
||||
if (!file_dialog_manager_) {
|
||||
file_dialog_manager_ = std::make_unique<CefFileDialogManager>(this);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "libcef/browser/browser_info.h"
|
||||
#include "libcef/browser/browser_platform_delegate.h"
|
||||
#include "libcef/browser/devtools/devtools_manager.h"
|
||||
#include "libcef/browser/file_dialog_manager.h"
|
||||
#include "libcef/browser/frame_host_impl.h"
|
||||
#include "libcef/browser/request_context_impl.h"
|
||||
|
||||
|
@ -156,6 +157,11 @@ class CefBrowserHostBase : public CefBrowserHost,
|
|||
CefRefPtr<CefRequestContext> GetRequestContext() override;
|
||||
bool HasView() override;
|
||||
void SetFocus(bool focus) override;
|
||||
void RunFileDialog(FileDialogMode mode,
|
||||
const CefString& title,
|
||||
const CefString& default_file_path,
|
||||
const std::vector<CefString>& accept_filters,
|
||||
CefRefPtr<CefRunFileDialogCallback> callback) override;
|
||||
void StartDownload(const CefString& url) override;
|
||||
void DownloadImage(const CefString& image_url,
|
||||
bool is_favicon,
|
||||
|
@ -234,6 +240,22 @@ class CefBrowserHostBase : public CefBrowserHost,
|
|||
virtual void OnSetFocus(cef_focus_source_t source) = 0;
|
||||
void ViewText(const std::string& text);
|
||||
|
||||
// Calls CefFileDialogManager methods.
|
||||
void RunFileChooserForBrowser(
|
||||
const blink::mojom::FileChooserParams& params,
|
||||
CefFileDialogManager::RunFileChooserCallback callback);
|
||||
void RunSelectFile(ui::SelectFileDialog::Listener* listener,
|
||||
std::unique_ptr<ui::SelectFilePolicy> policy,
|
||||
ui::SelectFileDialog::Type type,
|
||||
const std::u16string& title,
|
||||
const base::FilePath& default_path,
|
||||
const ui::SelectFileDialog::FileTypeInfo* file_types,
|
||||
int file_type_index,
|
||||
const base::FilePath::StringType& default_extension,
|
||||
gfx::NativeWindow owning_window,
|
||||
void* params);
|
||||
void SelectFileListenerDestroyed(ui::SelectFileDialog::Listener* listener);
|
||||
|
||||
// Called from CefBrowserInfoManager::MaybeAllowNavigation.
|
||||
virtual bool MaybeAllowNavigation(content::RenderFrameHost* opener,
|
||||
bool is_guest_view,
|
||||
|
@ -269,13 +291,27 @@ class CefBrowserHostBase : public CefBrowserHost,
|
|||
}
|
||||
|
||||
// Returns the Widget owner for the browser window. Only used with windowed
|
||||
// rendering.
|
||||
// browsers.
|
||||
views::Widget* GetWindowWidget() const;
|
||||
|
||||
// Returns the BrowserView associated with this browser. Only used with Views-
|
||||
// based browsers.
|
||||
CefRefPtr<CefBrowserView> GetBrowserView() const;
|
||||
|
||||
// Returns the top-level native window for this browser. With windowed
|
||||
// browsers this will be an aura::Window* on Aura platforms (Windows/Linux)
|
||||
// and an NSWindow wrapper object from native_widget_types.h on MacOS. With
|
||||
// windowless browsers this method will always return an empty value.
|
||||
gfx::NativeWindow GetTopLevelNativeWindow() const;
|
||||
|
||||
// Returns true if this browser is currently focused. A browser is considered
|
||||
// focused when the top-level RenderFrameHost is in the parent chain of the
|
||||
// currently focused RFH within the frame tree. In addition, its associated
|
||||
// RenderWidgetHost must also be focused. With windowed browsers only one
|
||||
// browser should be focused at a time. With windowless browsers this relies
|
||||
// on the client to properly configure focus state.
|
||||
bool IsFocused() const;
|
||||
|
||||
protected:
|
||||
bool EnsureDevToolsManager();
|
||||
void InitializeDevToolsRegistrationOnUIThread(
|
||||
|
@ -286,6 +322,9 @@ class CefBrowserHostBase : public CefBrowserHost,
|
|||
|
||||
void SetFocusInternal(bool focus);
|
||||
|
||||
// Create the CefFileDialogManager if it doesn't already exist.
|
||||
bool EnsureFileDialogManager();
|
||||
|
||||
// Thread-safe members.
|
||||
CefBrowserSettings settings_;
|
||||
CefRefPtr<CefClient> client_;
|
||||
|
@ -301,6 +340,9 @@ class CefBrowserHostBase : public CefBrowserHost,
|
|||
// Only accessed on the UI thread.
|
||||
base::ObserverList<Observer> observers_;
|
||||
|
||||
// Used for creating and managing file dialogs.
|
||||
std::unique_ptr<CefFileDialogManager> file_dialog_manager_;
|
||||
|
||||
// Volatile state accessed from multiple threads. All access must be protected
|
||||
// by |state_lock_|.
|
||||
base::Lock state_lock_;
|
||||
|
|
|
@ -223,12 +223,6 @@ CefEventHandle CefBrowserPlatformDelegate::GetEventHandle(
|
|||
return kNullEventHandle;
|
||||
}
|
||||
|
||||
std::unique_ptr<CefFileDialogRunner>
|
||||
CefBrowserPlatformDelegate::CreateFileDialogRunner() {
|
||||
NOTIMPLEMENTED();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<CefJavaScriptDialogRunner>
|
||||
CefBrowserPlatformDelegate::CreateJavaScriptDialogRunner() {
|
||||
NOTIMPLEMENTED();
|
||||
|
|
|
@ -63,7 +63,6 @@ class Widget;
|
|||
|
||||
struct CefBrowserCreateParams;
|
||||
class CefBrowserHostBase;
|
||||
class CefFileDialogRunner;
|
||||
class CefJavaScriptDialogRunner;
|
||||
class CefMenuRunner;
|
||||
|
||||
|
@ -266,9 +265,6 @@ class CefBrowserPlatformDelegate {
|
|||
virtual CefEventHandle GetEventHandle(
|
||||
const content::NativeWebKeyboardEvent& event) const;
|
||||
|
||||
// Create the platform-specific file dialog runner.
|
||||
virtual std::unique_ptr<CefFileDialogRunner> CreateFileDialogRunner();
|
||||
|
||||
// Create the platform-specific JavaScript dialog runner.
|
||||
virtual std::unique_ptr<CefJavaScriptDialogRunner>
|
||||
CreateJavaScriptDialogRunner();
|
||||
|
|
|
@ -186,17 +186,6 @@ void ChromeBrowserHostImpl::SetZoomLevel(double zoomLevel) {
|
|||
NOTIMPLEMENTED();
|
||||
}
|
||||
|
||||
void ChromeBrowserHostImpl::RunFileDialog(
|
||||
FileDialogMode mode,
|
||||
const CefString& title,
|
||||
const CefString& default_file_path,
|
||||
const std::vector<CefString>& accept_filters,
|
||||
int selected_accept_filter,
|
||||
CefRefPtr<CefRunFileDialogCallback> callback) {
|
||||
NOTIMPLEMENTED();
|
||||
callback->OnFileDialogDismissed(0, {});
|
||||
}
|
||||
|
||||
void ChromeBrowserHostImpl::Print() {
|
||||
if (!CEF_CURRENTLY_ON_UIT()) {
|
||||
CEF_POST_TASK(CEF_UIT, base::BindOnce(&ChromeBrowserHostImpl::Print, this));
|
||||
|
|
|
@ -66,12 +66,6 @@ class ChromeBrowserHostImpl : public CefBrowserHostBase {
|
|||
CefWindowHandle GetOpenerWindowHandle() override;
|
||||
double GetZoomLevel() override;
|
||||
void SetZoomLevel(double zoomLevel) override;
|
||||
void RunFileDialog(FileDialogMode mode,
|
||||
const CefString& title,
|
||||
const CefString& default_file_path,
|
||||
const std::vector<CefString>& accept_filters,
|
||||
int selected_accept_filter,
|
||||
CefRefPtr<CefRunFileDialogCallback> callback) override;
|
||||
void Print() override;
|
||||
void PrintToPDF(const CefString& path,
|
||||
const CefPdfPrintSettings& settings,
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -106,7 +106,7 @@ void CefDevToolsFileManager::Save(const std::string& url,
|
|||
}
|
||||
}
|
||||
|
||||
CefFileDialogRunner::FileChooserParams params;
|
||||
blink::mojom::FileChooserParams params;
|
||||
params.mode = blink::mojom::FileChooserParams::Mode::kSave;
|
||||
if (!initial_path.empty()) {
|
||||
params.default_file_name = initial_path;
|
||||
|
@ -115,7 +115,7 @@ void CefDevToolsFileManager::Save(const std::string& url,
|
|||
}
|
||||
}
|
||||
|
||||
browser_impl_->RunFileChooser(
|
||||
browser_impl_->RunFileChooserForBrowser(
|
||||
params,
|
||||
base::BindOnce(&CefDevToolsFileManager::SaveAsDialogDismissed,
|
||||
weak_factory_.GetWeakPtr(), url, content,
|
||||
|
@ -127,7 +127,6 @@ void CefDevToolsFileManager::SaveAsDialogDismissed(
|
|||
const std::string& content,
|
||||
SaveCallback saveCallback,
|
||||
CancelCallback cancelCallback,
|
||||
int selected_accept_filter,
|
||||
const std::vector<base::FilePath>& file_paths) {
|
||||
if (file_paths.size() == 1) {
|
||||
SaveAsFileSelected(url, content, std::move(saveCallback), file_paths[0]);
|
||||
|
|
|
@ -49,7 +49,6 @@ class CefDevToolsFileManager {
|
|||
const std::string& content,
|
||||
SaveCallback saveCallback,
|
||||
CancelCallback cancelCallback,
|
||||
int selected_accept_filter,
|
||||
const std::vector<base::FilePath>& file_paths);
|
||||
void SaveAsFileSelected(const std::string& url,
|
||||
const std::string& content,
|
||||
|
|
|
@ -136,7 +136,7 @@ class CefBeforeDownloadCallbackImpl : public CefBeforeDownloadCallback {
|
|||
if (browser.get()) {
|
||||
handled = true;
|
||||
|
||||
CefFileDialogRunner::FileChooserParams params;
|
||||
blink::mojom::FileChooserParams params;
|
||||
params.mode = blink::mojom::FileChooserParams::Mode::kSave;
|
||||
if (!suggested_path.empty()) {
|
||||
params.default_file_name = suggested_path;
|
||||
|
@ -146,7 +146,7 @@ class CefBeforeDownloadCallbackImpl : public CefBeforeDownloadCallback {
|
|||
}
|
||||
}
|
||||
|
||||
browser->RunFileChooser(
|
||||
browser->RunFileChooserForBrowser(
|
||||
params,
|
||||
base::BindOnce(
|
||||
&CefBeforeDownloadCallbackImpl::ChooseDownloadPathCallback,
|
||||
|
@ -166,7 +166,6 @@ class CefBeforeDownloadCallbackImpl : public CefBeforeDownloadCallback {
|
|||
|
||||
static void ChooseDownloadPathCallback(
|
||||
content::DownloadTargetCallback callback,
|
||||
int selected_accept_filter,
|
||||
const std::vector<base::FilePath>& file_paths) {
|
||||
DCHECK_LE(file_paths.size(), (size_t)1);
|
||||
|
||||
|
|
|
@ -4,18 +4,14 @@
|
|||
|
||||
#include "libcef/browser/extensions/api/file_system/cef_file_system_delegate.h"
|
||||
|
||||
#include "libcef/browser/alloy/alloy_dialog_util.h"
|
||||
|
||||
#include "apps/saved_files_service.h"
|
||||
#include "base/callback.h"
|
||||
#include "base/callback_forward.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "chrome/browser/extensions/api/file_system/file_entry_picker.h"
|
||||
#include "chrome/grit/generated_resources.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
#include "extensions/common/api/file_system.h"
|
||||
#include "extensions/common/extension.h"
|
||||
#include "third_party/abseil-cpp/absl/types/optional.h"
|
||||
|
||||
using blink::mojom::FileChooserParams;
|
||||
|
||||
namespace extensions {
|
||||
namespace cef {
|
||||
|
@ -46,61 +42,17 @@ bool CefFileSystemDelegate::ShowSelectFileDialog(
|
|||
return false;
|
||||
}
|
||||
|
||||
absl::optional<FileChooserParams::Mode> mode;
|
||||
switch (type) {
|
||||
case ui::SelectFileDialog::Type::SELECT_UPLOAD_FOLDER:
|
||||
mode = FileChooserParams::Mode::kUploadFolder;
|
||||
break;
|
||||
case ui::SelectFileDialog::Type::SELECT_SAVEAS_FILE:
|
||||
mode = FileChooserParams::Mode::kSave;
|
||||
break;
|
||||
case ui::SelectFileDialog::Type::SELECT_OPEN_FILE:
|
||||
mode = FileChooserParams::Mode::kOpen;
|
||||
break;
|
||||
case ui::SelectFileDialog::Type::SELECT_OPEN_MULTI_FILE:
|
||||
mode = FileChooserParams::Mode::kOpenMultiple;
|
||||
break;
|
||||
default:
|
||||
NOTIMPLEMENTED();
|
||||
return false;
|
||||
}
|
||||
|
||||
FileChooserParams params;
|
||||
params.mode = *mode;
|
||||
params.default_file_name = default_path;
|
||||
if (file_types) {
|
||||
// A list of allowed extensions. For example, it might be
|
||||
// { { "htm", "html" }, { "txt" } }
|
||||
for (auto& vec : file_types->extensions) {
|
||||
for (auto& ext : vec) {
|
||||
params.accept_types.push_back(
|
||||
alloy::FilePathTypeToString16(FILE_PATH_LITERAL(".") + ext));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
alloy::RunFileChooser(
|
||||
web_contents, params,
|
||||
base::BindOnce(&CefFileSystemDelegate::FileDialogDismissed,
|
||||
weak_ptr_factory_.GetWeakPtr(),
|
||||
// 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)));
|
||||
|
||||
std::move(file_selection_canceled_callback));
|
||||
return true;
|
||||
}
|
||||
|
||||
void CefFileSystemDelegate::FileDialogDismissed(
|
||||
FileSystemDelegate::FilesSelectedCallback files_selected_callback,
|
||||
base::OnceClosure file_selection_canceled_callback,
|
||||
int selected_accept_filter,
|
||||
const std::vector<base::FilePath>& file_paths) {
|
||||
if (!file_paths.empty()) {
|
||||
std::move(files_selected_callback).Run(file_paths);
|
||||
} else {
|
||||
std::move(file_selection_canceled_callback).Run();
|
||||
}
|
||||
}
|
||||
|
||||
void CefFileSystemDelegate::ConfirmSensitiveDirectoryAccess(
|
||||
bool has_write_permission,
|
||||
const std::u16string& app_name,
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
#include "base/callback.h"
|
||||
#include "base/compiler_specific.h"
|
||||
#include "base/memory/ref_counted.h"
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "extensions/browser/api/execute_code_function.h"
|
||||
#include "extensions/browser/api/file_system/file_system_delegate.h"
|
||||
#include "extensions/browser/extension_function.h"
|
||||
|
@ -51,15 +50,6 @@ class CefFileSystemDelegate : public FileSystemDelegate {
|
|||
int GetDescriptionIdForAcceptType(const std::string& accept_type) override;
|
||||
SavedFilesServiceInterface* GetSavedFilesService(
|
||||
content::BrowserContext* browser_context) override;
|
||||
|
||||
private:
|
||||
void FileDialogDismissed(
|
||||
FileSystemDelegate::FilesSelectedCallback files_selected_callback,
|
||||
base::OnceClosure file_selection_canceled_callback,
|
||||
int selected_accept_filter,
|
||||
const std::vector<base::FilePath>& file_paths);
|
||||
|
||||
base::WeakPtrFactory<CefFileSystemDelegate> weak_ptr_factory_{this};
|
||||
};
|
||||
|
||||
} // namespace cef
|
||||
|
|
|
@ -102,11 +102,6 @@ CefEventHandle CefBrowserPlatformDelegateBackground::GetEventHandle(
|
|||
return native_delegate_->GetEventHandle(event);
|
||||
}
|
||||
|
||||
std::unique_ptr<CefFileDialogRunner>
|
||||
CefBrowserPlatformDelegateBackground::CreateFileDialogRunner() {
|
||||
return native_delegate_->CreateFileDialogRunner();
|
||||
}
|
||||
|
||||
std::unique_ptr<CefJavaScriptDialogRunner>
|
||||
CefBrowserPlatformDelegateBackground::CreateJavaScriptDialogRunner() {
|
||||
return native_delegate_->CreateJavaScriptDialogRunner();
|
||||
|
|
|
@ -40,7 +40,6 @@ class CefBrowserPlatformDelegateBackground
|
|||
const content::NativeWebKeyboardEvent& event) override;
|
||||
CefEventHandle GetEventHandle(
|
||||
const content::NativeWebKeyboardEvent& event) const override;
|
||||
std::unique_ptr<CefFileDialogRunner> CreateFileDialogRunner() override;
|
||||
std::unique_ptr<CefJavaScriptDialogRunner> CreateJavaScriptDialogRunner()
|
||||
override;
|
||||
std::unique_ptr<CefMenuRunner> CreateMenuRunner() override;
|
||||
|
|
|
@ -8,18 +8,22 @@
|
|||
#include <utility>
|
||||
|
||||
#include "include/cef_dialog_handler.h"
|
||||
#include "libcef/browser/alloy/alloy_browser_host_impl.h"
|
||||
#include "libcef/browser/browser_host_base.h"
|
||||
#include "libcef/browser/context.h"
|
||||
#include "libcef/browser/thread_util.h"
|
||||
|
||||
#include "chrome/browser/file_select_helper.h"
|
||||
#include "content/public/browser/file_select_listener.h"
|
||||
#include "content/public/browser/render_frame_host.h"
|
||||
#include "net/base/directory_lister.h"
|
||||
#include "ui/shell_dialogs/select_file_policy.h"
|
||||
|
||||
using blink::mojom::FileChooserParams;
|
||||
|
||||
namespace {
|
||||
|
||||
class CefFileDialogCallbackImpl : public CefFileDialogCallback {
|
||||
public:
|
||||
using CallbackType = CefFileDialogRunner::RunFileChooserCallback;
|
||||
using CallbackType = CefFileDialogManager::RunFileChooserCallback;
|
||||
|
||||
explicit CefFileDialogCallbackImpl(CallbackType callback)
|
||||
: callback_(std::move(callback)) {}
|
||||
|
@ -37,8 +41,7 @@ class CefFileDialogCallbackImpl : public CefFileDialogCallback {
|
|||
}
|
||||
}
|
||||
|
||||
void Continue(int selected_accept_filter,
|
||||
const std::vector<CefString>& file_paths) override {
|
||||
void Continue(const std::vector<CefString>& file_paths) override {
|
||||
if (CEF_CURRENTLY_ON_UIT()) {
|
||||
if (!callback_.is_null()) {
|
||||
std::vector<base::FilePath> vec;
|
||||
|
@ -47,12 +50,12 @@ class CefFileDialogCallbackImpl : public CefFileDialogCallback {
|
|||
for (; it != file_paths.end(); ++it)
|
||||
vec.push_back(base::FilePath(*it));
|
||||
}
|
||||
std::move(callback_).Run(selected_accept_filter, vec);
|
||||
std::move(callback_).Run(vec);
|
||||
}
|
||||
} else {
|
||||
CEF_POST_TASK(CEF_UIT,
|
||||
base::BindOnce(&CefFileDialogCallbackImpl::Continue, this,
|
||||
selected_accept_filter, file_paths));
|
||||
file_paths));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -73,7 +76,7 @@ class CefFileDialogCallbackImpl : public CefFileDialogCallback {
|
|||
static void CancelNow(CallbackType callback) {
|
||||
CEF_REQUIRE_UIT();
|
||||
std::vector<base::FilePath> file_paths;
|
||||
std::move(callback).Run(0, file_paths);
|
||||
std::move(callback).Run(file_paths);
|
||||
}
|
||||
|
||||
CallbackType callback_;
|
||||
|
@ -82,77 +85,210 @@ class CefFileDialogCallbackImpl : public CefFileDialogCallback {
|
|||
};
|
||||
|
||||
void RunFileDialogDismissed(CefRefPtr<CefRunFileDialogCallback> callback,
|
||||
int selected_accept_filter,
|
||||
const std::vector<base::FilePath>& file_paths) {
|
||||
std::vector<CefString> paths;
|
||||
if (file_paths.size() > 0) {
|
||||
for (size_t i = 0; i < file_paths.size(); ++i)
|
||||
paths.push_back(file_paths[i].value());
|
||||
}
|
||||
callback->OnFileDialogDismissed(selected_accept_filter, paths);
|
||||
callback->OnFileDialogDismissed(paths);
|
||||
}
|
||||
|
||||
class UploadFolderHelper
|
||||
: public net::DirectoryLister::DirectoryListerDelegate {
|
||||
// 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;
|
||||
}
|
||||
|
||||
FileChooserParams SelectFileToFileChooserParams(
|
||||
ui::SelectFileDialog::Type type,
|
||||
const std::u16string& title,
|
||||
const base::FilePath& default_path,
|
||||
const ui::SelectFileDialog::FileTypeInfo* file_types) {
|
||||
FileChooserParams params;
|
||||
|
||||
absl::optional<FileChooserParams::Mode> mode;
|
||||
switch (type) {
|
||||
case ui::SelectFileDialog::Type::SELECT_UPLOAD_FOLDER:
|
||||
mode = FileChooserParams::Mode::kUploadFolder;
|
||||
break;
|
||||
case ui::SelectFileDialog::Type::SELECT_SAVEAS_FILE:
|
||||
mode = FileChooserParams::Mode::kSave;
|
||||
break;
|
||||
case ui::SelectFileDialog::Type::SELECT_OPEN_FILE:
|
||||
mode = FileChooserParams::Mode::kOpen;
|
||||
break;
|
||||
case ui::SelectFileDialog::Type::SELECT_OPEN_MULTI_FILE:
|
||||
mode = FileChooserParams::Mode::kOpenMultiple;
|
||||
break;
|
||||
default:
|
||||
NOTIMPLEMENTED();
|
||||
return params;
|
||||
}
|
||||
|
||||
params.mode = *mode;
|
||||
params.title = title;
|
||||
params.default_file_name = default_path;
|
||||
|
||||
// Note that this translation will lose any mime-type based filters that
|
||||
// may have existed in the original FileChooserParams::accept_types if this
|
||||
// dialog was created via FileSelectHelper::RunFileChooser.
|
||||
if (file_types) {
|
||||
// A list of allowed extensions. For example, it might be
|
||||
// { { "htm", "html" }, { "txt" } }
|
||||
for (auto& vec : file_types->extensions) {
|
||||
for (auto& ext : vec) {
|
||||
params.accept_types.push_back(
|
||||
FilePathTypeToString16(FILE_PATH_LITERAL(".") + ext));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
class CefFileSelectListener : public content::FileSelectListener {
|
||||
public:
|
||||
explicit UploadFolderHelper(
|
||||
CefFileDialogRunner::RunFileChooserCallback callback)
|
||||
using CallbackType = CefFileDialogManager::RunFileChooserCallback;
|
||||
|
||||
explicit CefFileSelectListener(CallbackType callback)
|
||||
: callback_(std::move(callback)) {}
|
||||
|
||||
UploadFolderHelper(const UploadFolderHelper&) = delete;
|
||||
UploadFolderHelper& operator=(const UploadFolderHelper&) = delete;
|
||||
|
||||
~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_)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OnListFile(
|
||||
const net::DirectoryLister::DirectoryListerData& data) override {
|
||||
CEF_REQUIRE_UIT();
|
||||
if (!data.info.IsDirectory())
|
||||
select_files_.push_back(data.path);
|
||||
}
|
||||
|
||||
void OnListDone(int error) override {
|
||||
CEF_REQUIRE_UIT();
|
||||
if (!callback_.is_null()) {
|
||||
std::move(callback_).Run(0, select_files_);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
static void CancelNow(CefFileDialogRunner::RunFileChooserCallback callback) {
|
||||
CEF_REQUIRE_UIT();
|
||||
std::vector<base::FilePath> file_paths;
|
||||
std::move(callback).Run(0, file_paths);
|
||||
~CefFileSelectListener() override = default;
|
||||
|
||||
void FileSelected(std::vector<blink::mojom::FileChooserFileInfoPtr> files,
|
||||
const base::FilePath& base_dir,
|
||||
FileChooserParams::Mode mode) override {
|
||||
std::vector<base::FilePath> paths;
|
||||
if (mode == FileChooserParams::Mode::kUploadFolder) {
|
||||
if (!base_dir.empty()) {
|
||||
paths.push_back(base_dir);
|
||||
}
|
||||
} else if (!files.empty()) {
|
||||
for (auto& file : files) {
|
||||
if (file->is_native_file()) {
|
||||
paths.push_back(file->get_native_file()->file_path);
|
||||
} else {
|
||||
NOTIMPLEMENTED();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CefFileDialogRunner::RunFileChooserCallback callback_;
|
||||
std::vector<base::FilePath> select_files_;
|
||||
std::move(callback_).Run(paths);
|
||||
}
|
||||
|
||||
void FileSelectionCanceled() override { std::move(callback_).Run({}); }
|
||||
|
||||
CallbackType callback_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
CefFileDialogManager::CefFileDialogManager(
|
||||
AlloyBrowserHostImpl* browser,
|
||||
std::unique_ptr<CefFileDialogRunner> runner)
|
||||
: browser_(browser),
|
||||
runner_(std::move(runner)),
|
||||
file_chooser_pending_(false),
|
||||
weak_ptr_factory_(this) {}
|
||||
class CefSelectFileDialogListener : public ui::SelectFileDialog::Listener {
|
||||
public:
|
||||
CefSelectFileDialogListener(ui::SelectFileDialog::Listener* listener,
|
||||
void* params,
|
||||
base::OnceClosure callback)
|
||||
: listener_(listener), params_(params), callback_(std::move(callback)) {}
|
||||
|
||||
CefFileDialogManager::~CefFileDialogManager() {}
|
||||
CefSelectFileDialogListener(const CefSelectFileDialogListener&) = delete;
|
||||
CefSelectFileDialogListener& operator=(const CefSelectFileDialogListener&) =
|
||||
delete;
|
||||
|
||||
void Cancel(bool listener_destroyed) {
|
||||
if (executing_) {
|
||||
// We're likely still on the stack. Do nothing and wait for Destroy().
|
||||
return;
|
||||
}
|
||||
if (listener_destroyed) {
|
||||
// Don't execute the listener.
|
||||
Destroy();
|
||||
} else {
|
||||
FileSelectionCanceled(params_);
|
||||
}
|
||||
}
|
||||
|
||||
ui::SelectFileDialog::Listener* listener() const { return listener_; }
|
||||
|
||||
private:
|
||||
~CefSelectFileDialogListener() override = default;
|
||||
|
||||
void FileSelected(const base::FilePath& path,
|
||||
int index,
|
||||
void* params) override {
|
||||
DCHECK_EQ(params, params_);
|
||||
executing_ = true;
|
||||
listener_->FileSelected(path, index, params);
|
||||
Destroy();
|
||||
}
|
||||
|
||||
void FileSelectedWithExtraInfo(const ui::SelectedFileInfo& file,
|
||||
int index,
|
||||
void* params) override {
|
||||
DCHECK_EQ(params, params_);
|
||||
executing_ = true;
|
||||
listener_->FileSelectedWithExtraInfo(file, index, params);
|
||||
Destroy();
|
||||
}
|
||||
|
||||
void MultiFilesSelected(const std::vector<base::FilePath>& files,
|
||||
void* params) override {
|
||||
DCHECK_EQ(params, params_);
|
||||
executing_ = true;
|
||||
listener_->MultiFilesSelected(files, params);
|
||||
Destroy();
|
||||
}
|
||||
|
||||
void MultiFilesSelectedWithExtraInfo(
|
||||
const std::vector<ui::SelectedFileInfo>& files,
|
||||
void* params) override {
|
||||
DCHECK_EQ(params, params_);
|
||||
executing_ = true;
|
||||
listener_->MultiFilesSelectedWithExtraInfo(files, params);
|
||||
Destroy();
|
||||
}
|
||||
|
||||
void FileSelectionCanceled(void* params) override {
|
||||
DCHECK_EQ(params, params_);
|
||||
executing_ = true;
|
||||
listener_->FileSelectionCanceled(params);
|
||||
Destroy();
|
||||
}
|
||||
|
||||
void Destroy() {
|
||||
std::move(callback_).Run();
|
||||
delete this;
|
||||
}
|
||||
|
||||
ui::SelectFileDialog::Listener* const listener_;
|
||||
void* const params_;
|
||||
base::OnceClosure callback_;
|
||||
|
||||
// Used to avoid re-entrancy from Cancel().
|
||||
bool executing_ = false;
|
||||
};
|
||||
|
||||
CefFileDialogManager::CefFileDialogManager(CefBrowserHostBase* browser)
|
||||
: browser_(browser) {}
|
||||
|
||||
CefFileDialogManager::~CefFileDialogManager() = default;
|
||||
|
||||
void CefFileDialogManager::Destroy() {
|
||||
DCHECK(!file_chooser_pending_);
|
||||
runner_.reset(nullptr);
|
||||
if (dialog_listener_) {
|
||||
// Cancel the listener and delete related objects.
|
||||
SelectFileDoneByListenerCallback(/*listener_destroyed=*/false);
|
||||
}
|
||||
DCHECK(!dialog_);
|
||||
DCHECK(!dialog_listener_);
|
||||
DCHECK(active_listeners_.empty());
|
||||
}
|
||||
|
||||
void CefFileDialogManager::RunFileDialog(
|
||||
|
@ -160,14 +296,13 @@ void CefFileDialogManager::RunFileDialog(
|
|||
const CefString& title,
|
||||
const CefString& default_file_path,
|
||||
const std::vector<CefString>& accept_filters,
|
||||
int selected_accept_filter,
|
||||
CefRefPtr<CefRunFileDialogCallback> callback) {
|
||||
DCHECK(callback.get());
|
||||
if (!callback.get())
|
||||
return;
|
||||
|
||||
CefFileDialogRunner::FileChooserParams params;
|
||||
switch (mode & FILE_DIALOG_TYPE_MASK) {
|
||||
blink::mojom::FileChooserParams params;
|
||||
switch (mode) {
|
||||
case FILE_DIALOG_OPEN:
|
||||
params.mode = blink::mojom::FileChooserParams::Mode::kOpen;
|
||||
break;
|
||||
|
@ -182,12 +317,6 @@ void CefFileDialogManager::RunFileDialog(
|
|||
break;
|
||||
}
|
||||
|
||||
DCHECK_GE(selected_accept_filter, 0);
|
||||
params.selected_accept_filter = selected_accept_filter;
|
||||
|
||||
params.overwriteprompt = !!(mode & FILE_DIALOG_OVERWRITEPROMPT_FLAG);
|
||||
params.hidereadonly = !!(mode & FILE_DIALOG_HIDEREADONLY_FLAG);
|
||||
|
||||
params.title = title;
|
||||
if (!default_file_path.empty())
|
||||
params.default_file_name = base::FilePath(default_file_path);
|
||||
|
@ -202,55 +331,145 @@ void CefFileDialogManager::RunFileDialog(
|
|||
}
|
||||
|
||||
void CefFileDialogManager::RunFileChooser(
|
||||
scoped_refptr<content::FileSelectListener> listener,
|
||||
const blink::mojom::FileChooserParams& params) {
|
||||
const blink::mojom::FileChooserParams& params,
|
||||
RunFileChooserCallback callback) {
|
||||
CEF_REQUIRE_UIT();
|
||||
|
||||
CefFileDialogRunner::FileChooserParams cef_params;
|
||||
static_cast<blink::mojom::FileChooserParams&>(cef_params) = params;
|
||||
|
||||
CefFileDialogRunner::RunFileChooserCallback callback;
|
||||
if (params.mode == blink::mojom::FileChooserParams::Mode::kUploadFolder) {
|
||||
callback = base::BindOnce(
|
||||
&CefFileDialogManager::OnRunFileChooserUploadFolderDelegateCallback,
|
||||
weak_ptr_factory_.GetWeakPtr(), params.mode, listener);
|
||||
} else {
|
||||
callback =
|
||||
base::BindOnce(&CefFileDialogManager::OnRunFileChooserDelegateCallback,
|
||||
weak_ptr_factory_.GetWeakPtr(), params.mode, listener);
|
||||
}
|
||||
|
||||
RunFileChooserInternal(cef_params, std::move(callback));
|
||||
}
|
||||
|
||||
void CefFileDialogManager::RunFileChooser(
|
||||
const CefFileDialogRunner::FileChooserParams& params,
|
||||
CefFileDialogRunner::RunFileChooserCallback callback) {
|
||||
CefFileDialogRunner::RunFileChooserCallback host_callback =
|
||||
base::BindOnce(&CefFileDialogManager::OnRunFileChooserCallback,
|
||||
weak_ptr_factory_.GetWeakPtr(), std::move(callback));
|
||||
RunFileChooserInternal(params, std::move(host_callback));
|
||||
}
|
||||
|
||||
void CefFileDialogManager::RunFileChooserInternal(
|
||||
const CefFileDialogRunner::FileChooserParams& params,
|
||||
CefFileDialogRunner::RunFileChooserCallback callback) {
|
||||
CEF_REQUIRE_UIT();
|
||||
|
||||
if (file_chooser_pending_) {
|
||||
// Dismiss the new dialog immediately.
|
||||
std::move(callback).Run(0, std::vector<base::FilePath>());
|
||||
// Execute the delegate with the most exact version of |params|. If not
|
||||
// handled here there will be another call to the delegate from RunSelectFile.
|
||||
// It might be better to execute the delegate only the single time here, but
|
||||
// we don't currently have sufficient state in RunSelectFile to know that the
|
||||
// delegate has already been executed.
|
||||
callback = MaybeRunDelegate(params, std::move(callback));
|
||||
if (callback.is_null()) {
|
||||
// The delegate kept the callback.
|
||||
return;
|
||||
}
|
||||
|
||||
file_chooser_pending_ = true;
|
||||
FileChooserParams new_params = params;
|
||||
|
||||
bool handled = false;
|
||||
// Make sure we get native files in CefFileSelectListener.
|
||||
new_params.need_local_path = true;
|
||||
|
||||
if (browser_->client().get()) {
|
||||
CefRefPtr<CefDialogHandler> handler =
|
||||
browser_->client()->GetDialogHandler();
|
||||
if (handler.get()) {
|
||||
// Requirements of FileSelectHelper.
|
||||
if (params.mode != FileChooserParams::Mode::kSave) {
|
||||
new_params.default_file_name = base::FilePath();
|
||||
} else {
|
||||
new_params.default_file_name = new_params.default_file_name.BaseName();
|
||||
}
|
||||
|
||||
// FileSelectHelper is usually only used for renderer-initiated dialogs via
|
||||
// WebContentsDelegate::RunFileChooser. We choose to use it here instead of
|
||||
// calling ui::SelectFileDialog::Create directly because it provides some nice
|
||||
// functionality related to default dialog settings and filter list
|
||||
// generation. We customize the behavior slightly for non-renderer-initiated
|
||||
// dialogs by passing the |run_from_cef=true| flag. FileSelectHelper uses
|
||||
// ui::SelectFileDialog::Create internally and that call will be intercepted
|
||||
// by CefSelectFileDialogFactory, resulting in call to RunSelectFile below.
|
||||
// See related comments on CefSelectFileDialogFactory.
|
||||
FileSelectHelper::RunFileChooser(
|
||||
browser_->GetWebContents()->GetMainFrame(),
|
||||
base::MakeRefCounted<CefFileSelectListener>(std::move(callback)),
|
||||
new_params, /*run_from_cef=*/true);
|
||||
}
|
||||
|
||||
void CefFileDialogManager::RunSelectFile(
|
||||
ui::SelectFileDialog::Listener* listener,
|
||||
std::unique_ptr<ui::SelectFilePolicy> policy,
|
||||
ui::SelectFileDialog::Type type,
|
||||
const std::u16string& title,
|
||||
const base::FilePath& default_path,
|
||||
const ui::SelectFileDialog::FileTypeInfo* file_types,
|
||||
int file_type_index,
|
||||
const base::FilePath::StringType& default_extension,
|
||||
gfx::NativeWindow owning_window,
|
||||
void* params) {
|
||||
CEF_REQUIRE_UIT();
|
||||
|
||||
active_listeners_.insert(listener);
|
||||
|
||||
// This will not be an exact representation of the original params.
|
||||
auto chooser_params =
|
||||
SelectFileToFileChooserParams(type, title, default_path, file_types);
|
||||
auto callback =
|
||||
base::BindOnce(&CefFileDialogManager::SelectFileDoneByDelegateCallback,
|
||||
weak_ptr_factory_.GetWeakPtr(), base::Unretained(listener),
|
||||
base::Unretained(params));
|
||||
callback = MaybeRunDelegate(chooser_params, std::move(callback));
|
||||
if (callback.is_null()) {
|
||||
// The delegate kept the callback.
|
||||
return;
|
||||
}
|
||||
|
||||
if (dialog_) {
|
||||
LOG(ERROR) << "Multiple simultaneous dialogs are not supported; "
|
||||
"canceling the file dialog";
|
||||
std::move(callback).Run({});
|
||||
return;
|
||||
}
|
||||
|
||||
#if BUILDFLAG(IS_LINUX)
|
||||
// We can't use GtkUi in combination with multi-threaded-message-loop because
|
||||
// Chromium's GTK implementation doesn't use GDK threads.
|
||||
if (!!CefContext::Get()->settings().multi_threaded_message_loop) {
|
||||
LOG(ERROR) << "Default dialog implementation is not available; "
|
||||
"canceling the file dialog";
|
||||
std::move(callback).Run({});
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
// |callback| is no longer used at this point.
|
||||
callback.Reset();
|
||||
|
||||
DCHECK(!dialog_listener_);
|
||||
|
||||
// This object will delete itself.
|
||||
dialog_listener_ = new CefSelectFileDialogListener(
|
||||
listener, params,
|
||||
base::BindOnce(&CefFileDialogManager::SelectFileDoneByListenerCallback,
|
||||
weak_ptr_factory_.GetWeakPtr(),
|
||||
/*listener_destroyed=*/false));
|
||||
|
||||
// This call will not be intercepted by CefSelectFileDialogFactory due to the
|
||||
// |run_from_cef=true| flag.
|
||||
// See related comments on CefSelectFileDialogFactory.
|
||||
dialog_ = ui::SelectFileDialog::Create(dialog_listener_, std::move(policy),
|
||||
/*run_from_cef=*/true);
|
||||
|
||||
// With windowless rendering use the parent handle specified by the client.
|
||||
if (browser_->IsWindowless()) {
|
||||
DCHECK(!owning_window);
|
||||
dialog_->set_owning_widget(browser_->GetWindowHandle());
|
||||
}
|
||||
|
||||
dialog_->SelectFile(type, title, default_path, file_types, file_type_index,
|
||||
default_extension, owning_window, params);
|
||||
}
|
||||
|
||||
void CefFileDialogManager::SelectFileListenerDestroyed(
|
||||
ui::SelectFileDialog::Listener* listener) {
|
||||
CEF_REQUIRE_UIT();
|
||||
DCHECK(listener);
|
||||
|
||||
// This notification will arrive from whomever owns |listener|, so we don't
|
||||
// want to execute any |listener| methods after this point.
|
||||
if (dialog_listener_ && listener == dialog_listener_->listener()) {
|
||||
// Cancel the currently active dialog.
|
||||
SelectFileDoneByListenerCallback(/*listener_destroyed=*/true);
|
||||
} else {
|
||||
// Any future SelectFileDoneByDelegateCallback call for |listener| becomes a
|
||||
// no-op.
|
||||
active_listeners_.erase(listener);
|
||||
}
|
||||
}
|
||||
|
||||
CefFileDialogManager::RunFileChooserCallback
|
||||
CefFileDialogManager::MaybeRunDelegate(
|
||||
const blink::mojom::FileChooserParams& params,
|
||||
RunFileChooserCallback callback) {
|
||||
if (auto client = browser_->client()) {
|
||||
if (auto handler = browser_->client()->GetDialogHandler()) {
|
||||
int mode = FILE_DIALOG_OPEN;
|
||||
switch (params.mode) {
|
||||
case blink::mojom::FileChooserParams::Mode::kOpen:
|
||||
|
@ -270,11 +489,6 @@ void CefFileDialogManager::RunFileChooserInternal(
|
|||
break;
|
||||
}
|
||||
|
||||
if (params.overwriteprompt)
|
||||
mode |= FILE_DIALOG_OVERWRITEPROMPT_FLAG;
|
||||
if (params.hidereadonly)
|
||||
mode |= FILE_DIALOG_HIDEREADONLY_FLAG;
|
||||
|
||||
std::vector<std::u16string>::const_iterator it;
|
||||
|
||||
std::vector<CefString> accept_filters;
|
||||
|
@ -284,10 +498,9 @@ void CefFileDialogManager::RunFileChooserInternal(
|
|||
|
||||
CefRefPtr<CefFileDialogCallbackImpl> callbackImpl(
|
||||
new CefFileDialogCallbackImpl(std::move(callback)));
|
||||
handled = handler->OnFileDialog(
|
||||
const bool handled = handler->OnFileDialog(
|
||||
browser_, static_cast<cef_file_dialog_mode_t>(mode), params.title,
|
||||
params.default_file_name.value(), accept_filters,
|
||||
params.selected_accept_filter, callbackImpl.get());
|
||||
params.default_file_name.value(), accept_filters, callbackImpl.get());
|
||||
if (!handled) {
|
||||
// May return nullptr if the client has already executed the callback.
|
||||
callback = callbackImpl->Disconnect();
|
||||
|
@ -295,82 +508,57 @@ void CefFileDialogManager::RunFileChooserInternal(
|
|||
}
|
||||
}
|
||||
|
||||
if (!handled && !callback.is_null()) {
|
||||
if (runner_.get()) {
|
||||
runner_->Run(browser_, params, std::move(callback));
|
||||
return callback;
|
||||
}
|
||||
|
||||
void CefFileDialogManager::SelectFileDoneByDelegateCallback(
|
||||
ui::SelectFileDialog::Listener* listener,
|
||||
void* params,
|
||||
const std::vector<base::FilePath>& paths) {
|
||||
CEF_REQUIRE_UIT();
|
||||
|
||||
// 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;
|
||||
|
||||
active_listeners_.erase(listener);
|
||||
|
||||
if (paths.empty()) {
|
||||
listener->FileSelectionCanceled(params);
|
||||
} else if (paths.size() == 1) {
|
||||
listener->FileSelected(paths[0], /*index=*/0, params);
|
||||
} else {
|
||||
LOG(WARNING) << "No file dialog runner available for this platform";
|
||||
std::move(callback).Run(0, std::vector<base::FilePath>());
|
||||
}
|
||||
listener->MultiFilesSelected(paths, params);
|
||||
}
|
||||
// |listener| is likely deleted at this point.
|
||||
}
|
||||
|
||||
void CefFileDialogManager::OnRunFileChooserCallback(
|
||||
CefFileDialogRunner::RunFileChooserCallback callback,
|
||||
int selected_accept_filter,
|
||||
const std::vector<base::FilePath>& file_paths) {
|
||||
void CefFileDialogManager::SelectFileDoneByListenerCallback(
|
||||
bool listener_destroyed) {
|
||||
CEF_REQUIRE_UIT();
|
||||
|
||||
Cleanup();
|
||||
// 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;
|
||||
|
||||
// Execute the callback asynchronously.
|
||||
CEF_POST_TASK(CEF_UIT, base::BindOnce(std::move(callback),
|
||||
selected_accept_filter, file_paths));
|
||||
}
|
||||
|
||||
void CefFileDialogManager::OnRunFileChooserUploadFolderDelegateCallback(
|
||||
const blink::mojom::FileChooserParams::Mode mode,
|
||||
scoped_refptr<content::FileSelectListener> listener,
|
||||
int selected_accept_filter,
|
||||
const std::vector<base::FilePath>& file_paths) {
|
||||
CEF_REQUIRE_UIT();
|
||||
DCHECK_EQ(mode, blink::mojom::FileChooserParams::Mode::kUploadFolder);
|
||||
|
||||
if (file_paths.size() == 0) {
|
||||
// Client canceled the file chooser.
|
||||
OnRunFileChooserDelegateCallback(mode, listener, selected_accept_filter,
|
||||
file_paths);
|
||||
} 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();
|
||||
}
|
||||
}
|
||||
|
||||
void CefFileDialogManager::OnRunFileChooserDelegateCallback(
|
||||
blink::mojom::FileChooserParams::Mode mode,
|
||||
scoped_refptr<content::FileSelectListener> listener,
|
||||
int selected_accept_filter,
|
||||
const std::vector<base::FilePath>& file_paths) {
|
||||
CEF_REQUIRE_UIT();
|
||||
|
||||
base::FilePath base_dir;
|
||||
std::vector<blink::mojom::FileChooserFileInfoPtr> selected_files;
|
||||
|
||||
if (!file_paths.empty()) {
|
||||
if (mode == blink::mojom::FileChooserParams::Mode::kUploadFolder) {
|
||||
base_dir = file_paths[0].DirName();
|
||||
}
|
||||
|
||||
// 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));
|
||||
}
|
||||
}
|
||||
|
||||
listener->FileSelected(std::move(selected_files), base_dir, mode);
|
||||
|
||||
Cleanup();
|
||||
}
|
||||
|
||||
void CefFileDialogManager::Cleanup() {
|
||||
if (lister_)
|
||||
lister_.reset();
|
||||
|
||||
file_chooser_pending_ = false;
|
||||
DCHECK(dialog_);
|
||||
DCHECK(dialog_listener_);
|
||||
|
||||
active_listeners_.erase(dialog_listener_->listener());
|
||||
|
||||
// Clear |dialog_listener_| before calling Cancel() to avoid re-entrancy.
|
||||
auto dialog_listener = dialog_listener_;
|
||||
dialog_listener_ = nullptr;
|
||||
dialog_listener->Cancel(listener_destroyed);
|
||||
|
||||
// There should be no further listener callbacks after this call.
|
||||
dialog_->ListenerDestroyed();
|
||||
dialog_ = nullptr;
|
||||
}
|
||||
|
|
|
@ -7,28 +7,25 @@
|
|||
#define CEF_LIBCEF_BROWSER_FILE_DIALOG_MANAGER_H_
|
||||
#pragma once
|
||||
|
||||
#include "include/cef_browser.h"
|
||||
#include "libcef/browser/file_dialog_runner.h"
|
||||
#include <memory>
|
||||
#include <set>
|
||||
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "content/public/browser/web_contents_observer.h"
|
||||
#include "include/cef_browser.h"
|
||||
|
||||
#include "base/memory/scoped_refptr.h"
|
||||
#include "third_party/blink/public/mojom/choosers/file_chooser.mojom.h"
|
||||
#include "ui/shell_dialogs/select_file_dialog.h"
|
||||
|
||||
namespace content {
|
||||
class FileSelectListener;
|
||||
class WebContents;
|
||||
} // namespace content
|
||||
|
||||
namespace net {
|
||||
class DirectoryLister;
|
||||
}
|
||||
|
||||
class AlloyBrowserHostImpl;
|
||||
class CefBrowserHostBase;
|
||||
class CefSelectFileDialogListener;
|
||||
|
||||
class CefFileDialogManager {
|
||||
public:
|
||||
// |runner| may be NULL if the platform doesn't implement dialogs.
|
||||
CefFileDialogManager(AlloyBrowserHostImpl* browser,
|
||||
std::unique_ptr<CefFileDialogRunner> runner);
|
||||
explicit CefFileDialogManager(CefBrowserHostBase* browser);
|
||||
|
||||
CefFileDialogManager(const CefFileDialogManager&) = delete;
|
||||
CefFileDialogManager& operator=(const CefFileDialogManager&) = delete;
|
||||
|
@ -38,70 +35,65 @@ class CefFileDialogManager {
|
|||
// Delete the runner to free any platform constructs.
|
||||
void Destroy();
|
||||
|
||||
// Called from AlloyBrowserHostImpl::RunFileChooser.
|
||||
// See CefBrowserHost::RunFileDialog documentation.
|
||||
// Run a file dialog with the specified parameters. See
|
||||
// CefBrowserHost::RunFileDialog for usage documentation. This method should
|
||||
// be called via CefBrowserHostBase::RunFileDialog.
|
||||
void RunFileDialog(cef_file_dialog_mode_t mode,
|
||||
const CefString& title,
|
||||
const CefString& default_file_path,
|
||||
const std::vector<CefString>& accept_filters,
|
||||
int selected_accept_filter,
|
||||
CefRefPtr<CefRunFileDialogCallback> callback);
|
||||
|
||||
// Called from AlloyBrowserHostImpl::RunFileChooser.
|
||||
// See WebContentsDelegate::RunFileChooser documentation.
|
||||
void RunFileChooser(scoped_refptr<content::FileSelectListener> listener,
|
||||
const blink::mojom::FileChooserParams& params);
|
||||
// The argument vector will be empty if the dialog was canceled.
|
||||
using RunFileChooserCallback =
|
||||
base::OnceCallback<void(const std::vector<base::FilePath>&)>;
|
||||
|
||||
// Run the file chooser dialog specified by |params|. Only a single dialog may
|
||||
// be pending at any given time. |callback| will be executed asynchronously
|
||||
// after the dialog is dismissed or if another dialog is already pending.
|
||||
void RunFileChooser(const CefFileDialogRunner::FileChooserParams& params,
|
||||
CefFileDialogRunner::RunFileChooserCallback callback);
|
||||
// Run the file dialog specified by |params|. |callback| will be executed
|
||||
// synchronously or asynchronously after the dialog is dismissed. This method
|
||||
// should be called via CefBrowserHostBase::RunFileChooser.
|
||||
void RunFileChooser(const blink::mojom::FileChooserParams& params,
|
||||
RunFileChooserCallback callback);
|
||||
|
||||
// Run a ui::SelectFileDialog with the specified parameters. See
|
||||
// ui::SelectFileDialog for usage documentation. This method should be called
|
||||
// via CefBrowserHostBase::RunSelectFile. It will be called for all file
|
||||
// dialogs after interception via CefSelectFileDialog::SelectFileImpl.
|
||||
void RunSelectFile(ui::SelectFileDialog::Listener* listener,
|
||||
std::unique_ptr<ui::SelectFilePolicy> policy,
|
||||
ui::SelectFileDialog::Type type,
|
||||
const std::u16string& title,
|
||||
const base::FilePath& default_path,
|
||||
const ui::SelectFileDialog::FileTypeInfo* file_types,
|
||||
int file_type_index,
|
||||
const base::FilePath::StringType& default_extension,
|
||||
gfx::NativeWindow owning_window,
|
||||
void* params);
|
||||
|
||||
// Must be called when the |listener| passed to RunSelectFile is destroyed.
|
||||
void SelectFileListenerDestroyed(ui::SelectFileDialog::Listener* listener);
|
||||
|
||||
private:
|
||||
void RunFileChooserInternal(
|
||||
const CefFileDialogRunner::FileChooserParams& params,
|
||||
CefFileDialogRunner::RunFileChooserCallback callback);
|
||||
[[nodiscard]] RunFileChooserCallback MaybeRunDelegate(
|
||||
const blink::mojom::FileChooserParams& params,
|
||||
RunFileChooserCallback callback);
|
||||
|
||||
// Used with the RunFileChooser variant where the caller specifies a callback
|
||||
// (no associated RenderFrameHost).
|
||||
void OnRunFileChooserCallback(
|
||||
CefFileDialogRunner::RunFileChooserCallback callback,
|
||||
int selected_accept_filter,
|
||||
const std::vector<base::FilePath>& file_paths);
|
||||
void SelectFileDoneByDelegateCallback(
|
||||
ui::SelectFileDialog::Listener* listener,
|
||||
void* params,
|
||||
const std::vector<base::FilePath>& paths);
|
||||
void SelectFileDoneByListenerCallback(bool listener_destroyed);
|
||||
|
||||
// Used with WebContentsDelegate::RunFileChooser when mode is
|
||||
// blink::mojom::FileChooserParams::Mode::kUploadFolder.
|
||||
void OnRunFileChooserUploadFolderDelegateCallback(
|
||||
const blink::mojom::FileChooserParams::Mode mode,
|
||||
scoped_refptr<content::FileSelectListener> listener,
|
||||
int selected_accept_filter,
|
||||
const std::vector<base::FilePath>& file_paths);
|
||||
// CefBrowserHostBase pointer is guaranteed to outlive this object.
|
||||
CefBrowserHostBase* const browser_;
|
||||
|
||||
// Used with WebContentsDelegate::RunFileChooser to notify the
|
||||
// RenderFrameHost.
|
||||
void OnRunFileChooserDelegateCallback(
|
||||
blink::mojom::FileChooserParams::Mode mode,
|
||||
scoped_refptr<content::FileSelectListener> listener,
|
||||
int selected_accept_filter,
|
||||
const std::vector<base::FilePath>& file_paths);
|
||||
// Used when running a platform dialog via RunSelectFile.
|
||||
scoped_refptr<ui::SelectFileDialog> dialog_;
|
||||
CefSelectFileDialogListener* dialog_listener_ = nullptr;
|
||||
|
||||
// Clean up state associated with the last run.
|
||||
void Cleanup();
|
||||
// List of all currently active listeners.
|
||||
std::set<ui::SelectFileDialog::Listener*> active_listeners_;
|
||||
|
||||
// AlloyBrowserHostImpl pointer is guaranteed to outlive this object.
|
||||
AlloyBrowserHostImpl* browser_;
|
||||
|
||||
std::unique_ptr<CefFileDialogRunner> runner_;
|
||||
|
||||
// True if a file chooser is currently pending.
|
||||
bool file_chooser_pending_;
|
||||
|
||||
// Used for asynchronously listing directory contents.
|
||||
std::unique_ptr<net::DirectoryLister> lister_;
|
||||
|
||||
// Must be the last member.
|
||||
base::WeakPtrFactory<CefFileDialogManager> weak_ptr_factory_;
|
||||
base::WeakPtrFactory<CefFileDialogManager> weak_ptr_factory_{this};
|
||||
};
|
||||
|
||||
#endif // CEF_LIBCEF_BROWSER_JAVASCRIPT_DIALOG_MANAGER_H_
|
||||
|
|
|
@ -0,0 +1,189 @@
|
|||
// Copyright (c) 2022 The Chromium Embedded Framework Authors.
|
||||
// Portions copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "libcef/browser/file_dialog_runner.h"
|
||||
|
||||
#include "libcef/browser/browser_host_base.h"
|
||||
#include "libcef/browser/browser_info_manager.h"
|
||||
#include "libcef/browser/extensions/browser_extensions_util.h"
|
||||
|
||||
#include "base/memory/singleton.h"
|
||||
#include "chrome/browser/file_select_helper.h"
|
||||
#include "chrome/browser/ui/chrome_select_file_policy.h"
|
||||
#include "ui/shell_dialogs/select_file_dialog_factory.h"
|
||||
#include "ui/shell_dialogs/select_file_policy.h"
|
||||
|
||||
using blink::mojom::FileChooserParams;
|
||||
|
||||
namespace {
|
||||
|
||||
// Creation of a file dialog can be triggered via various code paths, but they
|
||||
// all eventually result in a call to ui::SelectFileDialog::Create. We intercept
|
||||
// that call with CefSelectFileDialogFactory and redirect it to
|
||||
// CefFileDialogManager::RunSelectFile. After triggering the CefDialogHandler
|
||||
// callbacks that method calls ui::SelectFileDialog::Create again with
|
||||
// |run_from_cef=false| to trigger creation of the default platform dialog.
|
||||
class CefSelectFileDialogFactory final : public ui::SelectFileDialogFactory {
|
||||
public:
|
||||
CefSelectFileDialogFactory(const CefSelectFileDialogFactory&) = delete;
|
||||
CefSelectFileDialogFactory& operator=(const CefSelectFileDialogFactory&) =
|
||||
delete;
|
||||
|
||||
static CefSelectFileDialogFactory* GetInstance() {
|
||||
// Leaky because there is no useful cleanup to do.
|
||||
return base::Singleton<
|
||||
CefSelectFileDialogFactory,
|
||||
base::LeakySingletonTraits<CefSelectFileDialogFactory>>::get();
|
||||
}
|
||||
|
||||
ui::SelectFileDialog* Create(
|
||||
ui::SelectFileDialog::Listener* listener,
|
||||
std::unique_ptr<ui::SelectFilePolicy> policy) override;
|
||||
|
||||
bool IsCefFactory() const override { return true; }
|
||||
|
||||
private:
|
||||
friend struct base::DefaultSingletonTraits<CefSelectFileDialogFactory>;
|
||||
|
||||
CefSelectFileDialogFactory() { ui::SelectFileDialog::SetFactory(this); }
|
||||
};
|
||||
|
||||
CefRefPtr<CefBrowserHostBase> GetBrowserForTopLevelNativeWindow(
|
||||
gfx::NativeWindow owning_window) {
|
||||
DCHECK(owning_window);
|
||||
for (const auto& browser_info :
|
||||
CefBrowserInfoManager::GetInstance()->GetBrowserInfoList()) {
|
||||
if (auto browser = browser_info->browser()) {
|
||||
if (browser->GetTopLevelNativeWindow() == owning_window)
|
||||
return browser;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CefRefPtr<CefBrowserHostBase> GetLikelyFocusedBrowser() {
|
||||
for (const auto& browser_info :
|
||||
CefBrowserInfoManager::GetInstance()->GetBrowserInfoList()) {
|
||||
if (auto browser = browser_info->browser()) {
|
||||
if (browser->IsFocused())
|
||||
return browser;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Delegates the running of the dialog to CefFileDialogManager.
|
||||
class CefSelectFileDialog final : public ui::SelectFileDialog {
|
||||
public:
|
||||
CefSelectFileDialog(ui::SelectFileDialog::Listener* listener,
|
||||
std::unique_ptr<ui::SelectFilePolicy> policy)
|
||||
: ui::SelectFileDialog(listener, std::move(policy)) {
|
||||
DCHECK(listener_);
|
||||
}
|
||||
|
||||
CefSelectFileDialog(const CefSelectFileDialog&) = delete;
|
||||
CefSelectFileDialog& operator=(const CefSelectFileDialog&) = delete;
|
||||
|
||||
void SelectFileImpl(Type type,
|
||||
const std::u16string& title,
|
||||
const base::FilePath& default_path,
|
||||
const FileTypeInfo* file_types,
|
||||
int file_type_index,
|
||||
const base::FilePath::StringType& default_extension,
|
||||
gfx::NativeWindow owning_window,
|
||||
void* params) override {
|
||||
// Try to determine the associated browser (with decreasing levels of
|
||||
// confidence).
|
||||
// 1. Browser associated with the SelectFilePolicy. This is the most
|
||||
// reliable mechanism if specified at the SelectFileDialog::Create call
|
||||
// site.
|
||||
if (select_file_policy_) {
|
||||
auto chrome_policy =
|
||||
static_cast<ChromeSelectFilePolicy*>(select_file_policy_.get());
|
||||
auto web_contents = chrome_policy->source_contents();
|
||||
if (web_contents) {
|
||||
browser_ = extensions::GetOwnerBrowserForHost(
|
||||
web_contents->GetRenderViewHost(), nullptr);
|
||||
}
|
||||
if (!browser_) {
|
||||
LOG(WARNING) << "No browser associated with SelectFilePolicy";
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Browser associated with the top-level native window (owning_window).
|
||||
// This should be reliable with windowed browsers. However, |owning_window|
|
||||
// will always be nullptr with windowless browsers.
|
||||
if (!browser_ && owning_window) {
|
||||
browser_ = GetBrowserForTopLevelNativeWindow(owning_window);
|
||||
if (!browser_) {
|
||||
LOG(WARNING) << "No browser associated with top-level native window";
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Browser most likely to be focused. This may be somewhat iffy with
|
||||
// windowless browsers as there is no guarantee that the client has only
|
||||
// one browser focused at a time.
|
||||
if (!browser_) {
|
||||
browser_ = GetLikelyFocusedBrowser();
|
||||
if (!browser_) {
|
||||
LOG(WARNING) << "No likely focused browser";
|
||||
}
|
||||
}
|
||||
|
||||
if (!browser_) {
|
||||
LOG(ERROR)
|
||||
<< "Failed to identify associated browser; canceling the file dialog";
|
||||
listener_->FileSelectionCanceled(params);
|
||||
return;
|
||||
}
|
||||
|
||||
owning_window_ = owning_window;
|
||||
has_multiple_file_choices_ =
|
||||
file_types ? file_types->extensions.size() > 1 : true;
|
||||
|
||||
browser_->RunSelectFile(listener_, std::move(select_file_policy_), type,
|
||||
title, default_path, file_types, file_type_index,
|
||||
default_extension, owning_window, params);
|
||||
}
|
||||
|
||||
bool IsRunning(gfx::NativeWindow owning_window) const override {
|
||||
return owning_window == owning_window_;
|
||||
}
|
||||
|
||||
void ListenerDestroyed() override {
|
||||
if (browser_)
|
||||
browser_->SelectFileListenerDestroyed(listener_);
|
||||
listener_ = nullptr;
|
||||
}
|
||||
|
||||
bool HasMultipleFileTypeChoicesImpl() override {
|
||||
return has_multiple_file_choices_;
|
||||
}
|
||||
|
||||
private:
|
||||
gfx::NativeWindow owning_window_ = nullptr;
|
||||
bool has_multiple_file_choices_ = false;
|
||||
|
||||
CefRefPtr<CefBrowserHostBase> browser_;
|
||||
};
|
||||
|
||||
ui::SelectFileDialog* CefSelectFileDialogFactory::Create(
|
||||
ui::SelectFileDialog::Listener* listener,
|
||||
std::unique_ptr<ui::SelectFilePolicy> policy) {
|
||||
return new CefSelectFileDialog(listener, std::move(policy));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace file_dialog_runner {
|
||||
|
||||
void RegisterFactory() {
|
||||
// Implicitly registers on creation.
|
||||
CefSelectFileDialogFactory::GetInstance();
|
||||
}
|
||||
|
||||
} // namespace file_dialog_runner
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2012 The Chromium Embedded Framework Authors.
|
||||
// Copyright (c) 2022 The Chromium Embedded Framework Authors.
|
||||
// Portions copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
@ -7,46 +7,11 @@
|
|||
#define CEF_LIBCEF_BROWSER_FILE_DIALOG_RUNNER_H_
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
namespace file_dialog_runner {
|
||||
|
||||
#include "base/callback.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "third_party/blink/public/mojom/choosers/file_chooser.mojom.h"
|
||||
// One-time registration on startup.
|
||||
void RegisterFactory();
|
||||
|
||||
class AlloyBrowserHostImpl;
|
||||
|
||||
class CefFileDialogRunner {
|
||||
public:
|
||||
CefFileDialogRunner(const CefFileDialogRunner&) = delete;
|
||||
CefFileDialogRunner& operator=(const CefFileDialogRunner&) = delete;
|
||||
|
||||
// Extend blink::mojom::FileChooserParams with some options unique to CEF.
|
||||
struct FileChooserParams : public blink::mojom::FileChooserParams {
|
||||
// 0-based index of the selected value in |accept_types|.
|
||||
int selected_accept_filter = 0;
|
||||
|
||||
// True if the Save dialog should prompt before overwriting files.
|
||||
bool overwriteprompt = true;
|
||||
|
||||
// True if read-only files should be hidden.
|
||||
bool hidereadonly = true;
|
||||
};
|
||||
|
||||
// The argument vector will be empty if the dialog was canceled.
|
||||
using RunFileChooserCallback =
|
||||
base::OnceCallback<void(int, const std::vector<base::FilePath>&)>;
|
||||
|
||||
// Display the file chooser dialog. Execute |callback| on completion.
|
||||
virtual void Run(AlloyBrowserHostImpl* browser,
|
||||
const FileChooserParams& params,
|
||||
RunFileChooserCallback callback) = 0;
|
||||
|
||||
protected:
|
||||
// Allow deletion via std::unique_ptr only.
|
||||
friend std::default_delete<CefFileDialogRunner>;
|
||||
|
||||
CefFileDialogRunner() = default;
|
||||
virtual ~CefFileDialogRunner() = default;
|
||||
};
|
||||
} // namespace file_dialog_runner
|
||||
|
||||
#endif // CEF_LIBCEF_BROWSER_FILE_DIALOG_RUNNER_H_
|
||||
|
|
|
@ -40,7 +40,6 @@ class CefBrowserPlatformDelegateNativeMac
|
|||
const content::NativeWebKeyboardEvent& event) override;
|
||||
CefEventHandle GetEventHandle(
|
||||
const content::NativeWebKeyboardEvent& event) const override;
|
||||
std::unique_ptr<CefFileDialogRunner> CreateFileDialogRunner() override;
|
||||
std::unique_ptr<CefJavaScriptDialogRunner> CreateJavaScriptDialogRunner()
|
||||
override;
|
||||
std::unique_ptr<CefMenuRunner> CreateMenuRunner() override;
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
|
||||
#include "libcef/browser/alloy/alloy_browser_host_impl.h"
|
||||
#include "libcef/browser/context.h"
|
||||
#include "libcef/browser/native/file_dialog_runner_mac.h"
|
||||
#include "libcef/browser/native/javascript_dialog_runner_mac.h"
|
||||
#include "libcef/browser/native/menu_runner_mac.h"
|
||||
#include "libcef/browser/thread_util.h"
|
||||
|
@ -363,11 +362,6 @@ CefEventHandle CefBrowserPlatformDelegateNativeMac::GetEventHandle(
|
|||
return event.os_event;
|
||||
}
|
||||
|
||||
std::unique_ptr<CefFileDialogRunner>
|
||||
CefBrowserPlatformDelegateNativeMac::CreateFileDialogRunner() {
|
||||
return base::WrapUnique(new CefFileDialogRunnerMac);
|
||||
}
|
||||
|
||||
std::unique_ptr<CefJavaScriptDialogRunner>
|
||||
CefBrowserPlatformDelegateNativeMac::CreateJavaScriptDialogRunner() {
|
||||
return base::WrapUnique(new CefJavaScriptDialogRunnerMac);
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
|
||||
#include "libcef/browser/alloy/alloy_browser_host_impl.h"
|
||||
#include "libcef/browser/context.h"
|
||||
#include "libcef/browser/native/file_dialog_runner_win.h"
|
||||
#include "libcef/browser/native/javascript_dialog_runner_win.h"
|
||||
#include "libcef/browser/native/menu_runner_win.h"
|
||||
#include "libcef/browser/native/window_delegate_view.h"
|
||||
|
@ -447,11 +446,6 @@ CefEventHandle CefBrowserPlatformDelegateNativeWin::GetEventHandle(
|
|||
const_cast<CHROME_MSG*>(&event.os_event->native_event()));
|
||||
}
|
||||
|
||||
std::unique_ptr<CefFileDialogRunner>
|
||||
CefBrowserPlatformDelegateNativeWin::CreateFileDialogRunner() {
|
||||
return base::WrapUnique(new CefFileDialogRunnerWin);
|
||||
}
|
||||
|
||||
std::unique_ptr<CefJavaScriptDialogRunner>
|
||||
CefBrowserPlatformDelegateNativeWin::CreateJavaScriptDialogRunner() {
|
||||
return base::WrapUnique(new CefJavaScriptDialogRunnerWin);
|
||||
|
|
|
@ -34,7 +34,6 @@ class CefBrowserPlatformDelegateNativeWin
|
|||
const content::NativeWebKeyboardEvent& event) override;
|
||||
CefEventHandle GetEventHandle(
|
||||
const content::NativeWebKeyboardEvent& event) const override;
|
||||
std::unique_ptr<CefFileDialogRunner> CreateFileDialogRunner() override;
|
||||
std::unique_ptr<CefJavaScriptDialogRunner> CreateJavaScriptDialogRunner()
|
||||
override;
|
||||
std::unique_ptr<CefMenuRunner> CreateMenuRunner() override;
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
// Copyright (c) 2012 The Chromium Embedded Framework Authors.
|
||||
// Portions copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef CEF_LIBCEF_BROWSER_NATIVE_FILE_DIALOG_RUNNER_MAC_H_
|
||||
#define CEF_LIBCEF_BROWSER_NATIVE_FILE_DIALOG_RUNNER_MAC_H_
|
||||
#pragma once
|
||||
|
||||
#include "libcef/browser/file_dialog_runner.h"
|
||||
|
||||
#include "base/memory/weak_ptr.h"
|
||||
|
||||
@class NSView;
|
||||
|
||||
class CefFileDialogRunnerMac : public CefFileDialogRunner {
|
||||
public:
|
||||
CefFileDialogRunnerMac();
|
||||
|
||||
// CefFileDialogRunner methods:
|
||||
void Run(AlloyBrowserHostImpl* browser,
|
||||
const FileChooserParams& params,
|
||||
RunFileChooserCallback callback) override;
|
||||
|
||||
private:
|
||||
static void RunOpenFileDialog(
|
||||
base::WeakPtr<CefFileDialogRunnerMac> weak_this,
|
||||
const CefFileDialogRunner::FileChooserParams& params,
|
||||
NSView* view,
|
||||
int filter_index);
|
||||
static void RunSaveFileDialog(
|
||||
base::WeakPtr<CefFileDialogRunnerMac> weak_this,
|
||||
const CefFileDialogRunner::FileChooserParams& params,
|
||||
NSView* view,
|
||||
int filter_index);
|
||||
|
||||
CefFileDialogRunner::RunFileChooserCallback callback_;
|
||||
base::WeakPtrFactory<CefFileDialogRunnerMac> weak_ptr_factory_;
|
||||
};
|
||||
|
||||
#endif // CEF_LIBCEF_BROWSER_NATIVE_FILE_DIALOG_RUNNER_MAC_H_
|
|
@ -1,405 +0,0 @@
|
|||
// Copyright (c) 2012 The Chromium Embedded Framework Authors.
|
||||
// Portions copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "libcef/browser/native/file_dialog_runner_mac.h"
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <CoreServices/CoreServices.h>
|
||||
|
||||
#include "libcef/browser/alloy/alloy_browser_host_impl.h"
|
||||
|
||||
#include "base/mac/mac_util.h"
|
||||
#include "base/stl_util.h"
|
||||
#include "base/strings/string_split.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/strings/sys_string_conversions.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "base/threading/thread_restrictions.h"
|
||||
#include "cef/grit/cef_strings.h"
|
||||
#include "chrome/grit/generated_resources.h"
|
||||
#include "net/base/mime_util.h"
|
||||
#include "ui/base/l10n/l10n_util.h"
|
||||
#include "ui/strings/grit/ui_strings.h"
|
||||
|
||||
namespace {
|
||||
|
||||
std::u16string GetDescriptionFromMimeType(const std::string& mime_type) {
|
||||
// Check for wild card mime types and return an appropriate description.
|
||||
static const struct {
|
||||
const char* mime_type;
|
||||
int string_id;
|
||||
} kWildCardMimeTypes[] = {
|
||||
{"audio", IDS_AUDIO_FILES},
|
||||
{"image", IDS_IMAGE_FILES},
|
||||
{"text", IDS_TEXT_FILES},
|
||||
{"video", IDS_VIDEO_FILES},
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < std::size(kWildCardMimeTypes); ++i) {
|
||||
if (mime_type == std::string(kWildCardMimeTypes[i].mime_type) + "/*")
|
||||
return l10n_util::GetStringUTF16(kWildCardMimeTypes[i].string_id);
|
||||
}
|
||||
|
||||
return std::u16string();
|
||||
}
|
||||
|
||||
void AddFilters(NSPopUpButton* button,
|
||||
const std::vector<std::u16string>& accept_filters,
|
||||
bool include_all_files,
|
||||
std::vector<std::vector<std::u16string>>* all_extensions) {
|
||||
for (size_t i = 0; i < accept_filters.size(); ++i) {
|
||||
const std::u16string& filter = accept_filters[i];
|
||||
if (filter.empty())
|
||||
continue;
|
||||
|
||||
std::vector<std::u16string> extensions;
|
||||
std::u16string description;
|
||||
|
||||
size_t sep_index = filter.find('|');
|
||||
if (sep_index != std::string::npos) {
|
||||
// Treat as a filter of the form "Filter Name|.ext1;.ext2;.ext3".
|
||||
description = filter.substr(0, sep_index);
|
||||
|
||||
const std::vector<std::u16string>& ext =
|
||||
base::SplitString(filter.substr(sep_index + 1), u";",
|
||||
base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
|
||||
for (size_t x = 0; x < ext.size(); ++x) {
|
||||
const std::u16string& file_ext = ext[x];
|
||||
if (!file_ext.empty() && file_ext[0] == '.')
|
||||
extensions.push_back(file_ext);
|
||||
}
|
||||
} else if (filter[0] == '.') {
|
||||
// Treat as an extension beginning with the '.' character.
|
||||
extensions.push_back(filter);
|
||||
} else {
|
||||
// Otherwise convert mime type to one or more extensions.
|
||||
const std::string& ascii = base::UTF16ToASCII(filter);
|
||||
std::vector<base::FilePath::StringType> ext;
|
||||
net::GetExtensionsForMimeType(ascii, &ext);
|
||||
if (!ext.empty()) {
|
||||
for (size_t x = 0; x < ext.size(); ++x)
|
||||
extensions.push_back(u"." + base::ASCIIToUTF16(ext[x]));
|
||||
description = GetDescriptionFromMimeType(ascii);
|
||||
}
|
||||
}
|
||||
|
||||
if (extensions.empty())
|
||||
continue;
|
||||
|
||||
// Don't display a crazy number of extensions since the NSPopUpButton width
|
||||
// will keep growing.
|
||||
const size_t kMaxExtensions = 10;
|
||||
|
||||
std::u16string ext_str;
|
||||
for (size_t x = 0; x < std::min(kMaxExtensions, extensions.size()); ++x) {
|
||||
const std::u16string& pattern = u"*" + extensions[x];
|
||||
if (x != 0)
|
||||
ext_str += u";";
|
||||
ext_str += pattern;
|
||||
}
|
||||
|
||||
if (extensions.size() > kMaxExtensions)
|
||||
ext_str += u";...";
|
||||
|
||||
if (description.empty()) {
|
||||
description = ext_str;
|
||||
} else {
|
||||
description += u" (" + ext_str + u")";
|
||||
}
|
||||
|
||||
[button addItemWithTitle:base::SysUTF16ToNSString(description)];
|
||||
|
||||
all_extensions->push_back(extensions);
|
||||
}
|
||||
|
||||
// Add the *.* filter, but only if we have added other filters (otherwise it
|
||||
// is implied).
|
||||
if (include_all_files && !all_extensions->empty()) {
|
||||
[button addItemWithTitle:base::SysUTF8ToNSString("All Files (*)")];
|
||||
all_extensions->push_back(std::vector<std::u16string>());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// Used to manage the file type filter in the NSSavePanel/NSOpenPanel.
|
||||
@interface CefFilterDelegate : NSObject {
|
||||
@private
|
||||
NSSavePanel* panel_;
|
||||
std::vector<std::vector<std::u16string>> extensions_;
|
||||
int selected_index_;
|
||||
}
|
||||
- (id)initWithPanel:(NSSavePanel*)panel
|
||||
andAcceptFilters:(const std::vector<std::u16string>&)accept_filters
|
||||
andFilterIndex:(int)index;
|
||||
- (void)setFilter:(int)index;
|
||||
- (int)filter;
|
||||
- (void)filterSelectionChanged:(id)sender;
|
||||
- (void)setFileExtension;
|
||||
@end
|
||||
|
||||
@implementation CefFilterDelegate
|
||||
|
||||
- (id)initWithPanel:(NSSavePanel*)panel
|
||||
andAcceptFilters:(const std::vector<std::u16string>&)accept_filters
|
||||
andFilterIndex:(int)index {
|
||||
if (self = [super init]) {
|
||||
DCHECK(panel);
|
||||
panel_ = panel;
|
||||
selected_index_ = 0;
|
||||
|
||||
NSPopUpButton* button = [[NSPopUpButton alloc] init];
|
||||
AddFilters(button, accept_filters, true, &extensions_);
|
||||
[button sizeToFit];
|
||||
[button setTarget:self];
|
||||
[button setAction:@selector(filterSelectionChanged:)];
|
||||
|
||||
if (index < static_cast<int>(extensions_.size())) {
|
||||
[button selectItemAtIndex:index];
|
||||
[self setFilter:index];
|
||||
}
|
||||
|
||||
[panel_ setAccessoryView:button];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
// Set the current filter index.
|
||||
- (void)setFilter:(int)index {
|
||||
DCHECK(index >= 0 && index < static_cast<int>(extensions_.size()));
|
||||
selected_index_ = index;
|
||||
|
||||
// Set the selectable file types. For open panels this limits the files that
|
||||
// can be selected. For save panels this applies a default file extenion when
|
||||
// the dialog is dismissed if none is already provided.
|
||||
NSMutableArray* acceptArray = nil;
|
||||
if (!extensions_[index].empty()) {
|
||||
acceptArray = [[NSMutableArray alloc] init];
|
||||
for (size_t i = 0; i < extensions_[index].size(); ++i) {
|
||||
[acceptArray
|
||||
addObject:base::SysUTF16ToNSString(extensions_[index][i].substr(1))];
|
||||
}
|
||||
}
|
||||
[panel_ setAllowedFileTypes:acceptArray];
|
||||
|
||||
if (![panel_ isKindOfClass:[NSOpenPanel class]]) {
|
||||
// For save panels set the file extension.
|
||||
[self setFileExtension];
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the current filter index.
|
||||
- (int)filter {
|
||||
return selected_index_;
|
||||
}
|
||||
|
||||
// Called when the selected filter is changed via the NSPopUpButton.
|
||||
- (void)filterSelectionChanged:(id)sender {
|
||||
NSPopUpButton* button = (NSPopUpButton*)sender;
|
||||
[self setFilter:[button indexOfSelectedItem]];
|
||||
}
|
||||
|
||||
// Set the extension on the currently selected file name.
|
||||
- (void)setFileExtension {
|
||||
const std::vector<std::u16string>& filter = extensions_[selected_index_];
|
||||
if (filter.empty()) {
|
||||
// All extensions are allowed so don't change anything.
|
||||
return;
|
||||
}
|
||||
|
||||
base::FilePath path(base::SysNSStringToUTF8([panel_ nameFieldStringValue]));
|
||||
|
||||
// If the file name currently includes an extension from |filter| then don't
|
||||
// change anything.
|
||||
std::u16string extension = base::UTF8ToUTF16(path.Extension());
|
||||
if (!extension.empty()) {
|
||||
for (size_t i = 0; i < filter.size(); ++i) {
|
||||
if (filter[i] == extension)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Change the extension to the first value in |filter|.
|
||||
path = path.ReplaceExtension(base::UTF16ToUTF8(filter[0]));
|
||||
[panel_ setNameFieldStringValue:base::SysUTF8ToNSString(path.value())];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
CefFileDialogRunnerMac::CefFileDialogRunnerMac() : weak_ptr_factory_(this) {}
|
||||
|
||||
void CefFileDialogRunnerMac::Run(AlloyBrowserHostImpl* browser,
|
||||
const FileChooserParams& params,
|
||||
RunFileChooserCallback callback) {
|
||||
callback_ = std::move(callback);
|
||||
|
||||
int filter_index = params.selected_accept_filter;
|
||||
NSView* owner = CAST_CEF_WINDOW_HANDLE_TO_NSVIEW(browser->GetWindowHandle());
|
||||
auto weak_this = weak_ptr_factory_.GetWeakPtr();
|
||||
|
||||
if (params.mode == blink::mojom::FileChooserParams::Mode::kOpen ||
|
||||
params.mode == blink::mojom::FileChooserParams::Mode::kOpenMultiple ||
|
||||
params.mode == blink::mojom::FileChooserParams::Mode::kUploadFolder) {
|
||||
RunOpenFileDialog(weak_this, params, owner, filter_index);
|
||||
} else if (params.mode == blink::mojom::FileChooserParams::Mode::kSave) {
|
||||
RunSaveFileDialog(weak_this, params, owner, filter_index);
|
||||
} else {
|
||||
NOTIMPLEMENTED();
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
void CefFileDialogRunnerMac::RunOpenFileDialog(
|
||||
base::WeakPtr<CefFileDialogRunnerMac> weak_this,
|
||||
const CefFileDialogRunner::FileChooserParams& params,
|
||||
NSView* view,
|
||||
int filter_index) {
|
||||
NSOpenPanel* openPanel = [NSOpenPanel openPanel];
|
||||
|
||||
std::u16string title;
|
||||
if (!params.title.empty()) {
|
||||
title = params.title;
|
||||
} else {
|
||||
title = l10n_util::GetStringUTF16(
|
||||
params.mode == blink::mojom::FileChooserParams::Mode::kOpen
|
||||
? IDS_OPEN_FILE_DIALOG_TITLE
|
||||
: (params.mode ==
|
||||
blink::mojom::FileChooserParams::Mode::kOpenMultiple
|
||||
? IDS_OPEN_FILES_DIALOG_TITLE
|
||||
: IDS_SELECT_FOLDER_DIALOG_TITLE));
|
||||
}
|
||||
[openPanel setTitle:base::SysUTF16ToNSString(title)];
|
||||
|
||||
std::string filename, directory;
|
||||
if (!params.default_file_name.empty()) {
|
||||
if (params.mode == blink::mojom::FileChooserParams::Mode::kUploadFolder ||
|
||||
params.default_file_name.EndsWithSeparator()) {
|
||||
// The value is only a directory.
|
||||
directory = params.default_file_name.value();
|
||||
} else {
|
||||
// The value is a file name and possibly a directory.
|
||||
filename = params.default_file_name.BaseName().value();
|
||||
directory = params.default_file_name.DirName().value();
|
||||
}
|
||||
}
|
||||
if (!filename.empty()) {
|
||||
[openPanel setNameFieldStringValue:base::SysUTF8ToNSString(filename)];
|
||||
}
|
||||
if (!directory.empty()) {
|
||||
[openPanel setDirectoryURL:[NSURL fileURLWithPath:base::SysUTF8ToNSString(
|
||||
directory)]];
|
||||
}
|
||||
|
||||
CefFilterDelegate* filter_delegate = nil;
|
||||
if (params.mode != blink::mojom::FileChooserParams::Mode::kUploadFolder &&
|
||||
!params.accept_types.empty()) {
|
||||
// Add the file filter control.
|
||||
filter_delegate =
|
||||
[[CefFilterDelegate alloc] initWithPanel:openPanel
|
||||
andAcceptFilters:params.accept_types
|
||||
andFilterIndex:filter_index];
|
||||
}
|
||||
|
||||
// Further panel configuration.
|
||||
[openPanel setAllowsOtherFileTypes:YES];
|
||||
[openPanel setAllowsMultipleSelection:
|
||||
(params.mode ==
|
||||
blink::mojom::FileChooserParams::Mode::kOpenMultiple)];
|
||||
[openPanel
|
||||
setCanChooseFiles:(params.mode !=
|
||||
blink::mojom::FileChooserParams::Mode::kUploadFolder)];
|
||||
[openPanel
|
||||
setCanChooseDirectories:(params.mode == blink::mojom::FileChooserParams::
|
||||
Mode::kUploadFolder)];
|
||||
[openPanel setShowsHiddenFiles:!params.hidereadonly];
|
||||
|
||||
// Show panel.
|
||||
[openPanel
|
||||
beginSheetModalForWindow:[view window]
|
||||
completionHandler:^(NSInteger returnCode) {
|
||||
int filter_index_to_use = (filter_delegate != nil)
|
||||
? [filter_delegate filter]
|
||||
: filter_index;
|
||||
if (returnCode == NSFileHandlingPanelOKButton) {
|
||||
std::vector<base::FilePath> files;
|
||||
files.reserve(openPanel.URLs.count);
|
||||
for (NSURL* url in openPanel.URLs) {
|
||||
if (url.isFileURL)
|
||||
files.push_back(base::FilePath(url.path.UTF8String));
|
||||
}
|
||||
std::move(weak_this->callback_)
|
||||
.Run(filter_index_to_use, files);
|
||||
} else {
|
||||
std::move(weak_this->callback_)
|
||||
.Run(filter_index_to_use, std::vector<base::FilePath>());
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
// static
|
||||
void CefFileDialogRunnerMac::RunSaveFileDialog(
|
||||
base::WeakPtr<CefFileDialogRunnerMac> weak_this,
|
||||
const CefFileDialogRunner::FileChooserParams& params,
|
||||
NSView* view,
|
||||
int filter_index) {
|
||||
NSSavePanel* savePanel = [NSSavePanel savePanel];
|
||||
|
||||
std::u16string title;
|
||||
if (!params.title.empty())
|
||||
title = params.title;
|
||||
else
|
||||
title = l10n_util::GetStringUTF16(IDS_SAVE_AS_DIALOG_TITLE);
|
||||
[savePanel setTitle:base::SysUTF16ToNSString(title)];
|
||||
|
||||
std::string filename, directory;
|
||||
if (!params.default_file_name.empty()) {
|
||||
if (params.default_file_name.EndsWithSeparator()) {
|
||||
// The value is only a directory.
|
||||
directory = params.default_file_name.value();
|
||||
} else {
|
||||
// The value is a file name and possibly a directory.
|
||||
filename = params.default_file_name.BaseName().value();
|
||||
directory = params.default_file_name.DirName().value();
|
||||
}
|
||||
}
|
||||
if (!filename.empty()) {
|
||||
[savePanel setNameFieldStringValue:base::SysUTF8ToNSString(filename)];
|
||||
}
|
||||
if (!directory.empty()) {
|
||||
[savePanel setDirectoryURL:[NSURL fileURLWithPath:base::SysUTF8ToNSString(
|
||||
directory)]];
|
||||
}
|
||||
|
||||
CefFilterDelegate* filter_delegate = nil;
|
||||
if (!params.accept_types.empty()) {
|
||||
// Add the file filter control.
|
||||
filter_delegate =
|
||||
[[CefFilterDelegate alloc] initWithPanel:savePanel
|
||||
andAcceptFilters:params.accept_types
|
||||
andFilterIndex:filter_index];
|
||||
}
|
||||
|
||||
[savePanel setAllowsOtherFileTypes:YES];
|
||||
[savePanel setShowsHiddenFiles:!params.hidereadonly];
|
||||
|
||||
// Show panel.
|
||||
[savePanel
|
||||
beginSheetModalForWindow:view.window
|
||||
completionHandler:^(NSInteger resultCode) {
|
||||
int filter_index_to_use = (filter_delegate != nil)
|
||||
? [filter_delegate filter]
|
||||
: filter_index;
|
||||
if (resultCode == NSFileHandlingPanelOKButton) {
|
||||
NSURL* url = savePanel.URL;
|
||||
const char* path = url.path.UTF8String;
|
||||
std::vector<base::FilePath> files(1, base::FilePath(path));
|
||||
std::move(weak_this->callback_)
|
||||
.Run(filter_index_to_use, files);
|
||||
} else {
|
||||
std::move(weak_this->callback_)
|
||||
.Run(filter_index_to_use, std::vector<base::FilePath>());
|
||||
}
|
||||
}];
|
||||
}
|
|
@ -1,560 +0,0 @@
|
|||
// Copyright (c) 2012 The Chromium Embedded Framework Authors.
|
||||
// Portions copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "libcef/browser/native/file_dialog_runner_win.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <commdlg.h>
|
||||
#include <shlobj.h>
|
||||
#include <wrl/client.h>
|
||||
|
||||
#include "libcef/browser/alloy/alloy_browser_host_impl.h"
|
||||
|
||||
#include "base/files/file_util.h"
|
||||
#include "base/stl_util.h"
|
||||
#include "base/strings/string_split.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "base/win/registry.h"
|
||||
#include "cef/grit/cef_strings.h"
|
||||
#include "chrome/grit/generated_resources.h"
|
||||
#include "net/base/mime_util.h"
|
||||
#include "ui/base/l10n/l10n_util.h"
|
||||
#include "ui/base/win/shell.h"
|
||||
#include "ui/strings/grit/ui_strings.h"
|
||||
|
||||
namespace {
|
||||
|
||||
// From ui/base/dialogs/select_file_dialog_win.cc.
|
||||
|
||||
// Get the file type description from the registry. This will be "Text Document"
|
||||
// for .txt files, "JPEG Image" for .jpg files, etc. If the registry doesn't
|
||||
// have an entry for the file type, we return false, true if the description was
|
||||
// found. 'file_ext' must be in form ".txt".
|
||||
static bool GetRegistryDescriptionFromExtension(const std::wstring& file_ext,
|
||||
std::wstring* reg_description) {
|
||||
DCHECK(reg_description);
|
||||
base::win::RegKey reg_ext(HKEY_CLASSES_ROOT, file_ext.c_str(), KEY_READ);
|
||||
std::wstring reg_app;
|
||||
if (reg_ext.ReadValue(NULL, ®_app) == ERROR_SUCCESS && !reg_app.empty()) {
|
||||
base::win::RegKey reg_link(HKEY_CLASSES_ROOT, reg_app.c_str(), KEY_READ);
|
||||
if (reg_link.ReadValue(NULL, reg_description) == ERROR_SUCCESS)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set up a filter for a Save/Open dialog, which will consist of |file_ext| file
|
||||
// extensions (internally separated by semicolons), |ext_desc| as the text
|
||||
// descriptions of the |file_ext| types (optional), and (optionally) the default
|
||||
// 'All Files' view. The purpose of the filter is to show only files of a
|
||||
// particular type in a Windows Save/Open dialog box. The resulting filter is
|
||||
// returned. The filters created here are:
|
||||
// 1. only files that have 'file_ext' as their extension
|
||||
// 2. all files (only added if 'include_all_files' is true)
|
||||
// Example:
|
||||
// file_ext: { "*.txt", "*.htm;*.html" }
|
||||
// ext_desc: { "Text Document" }
|
||||
// returned: "Text Document\0*.txt\0HTML Document\0*.htm;*.html\0"
|
||||
// "All Files\0*.*\0\0" (in one big string)
|
||||
// If a description is not provided for a file extension, it will be retrieved
|
||||
// from the registry. If the file extension does not exist in the registry, it
|
||||
// will be omitted from the filter, as it is likely a bogus extension.
|
||||
std::wstring FormatFilterForExtensions(
|
||||
const std::vector<std::wstring>& file_ext,
|
||||
const std::vector<std::wstring>& ext_desc,
|
||||
bool include_all_files) {
|
||||
const std::wstring all_ext = L"*.*";
|
||||
const std::wstring all_desc =
|
||||
base::UTF16ToWide(l10n_util::GetStringUTF16(IDS_APP_SAVEAS_ALL_FILES)) +
|
||||
L" (" + all_ext + L")";
|
||||
|
||||
DCHECK(file_ext.size() >= ext_desc.size());
|
||||
|
||||
if (file_ext.empty())
|
||||
include_all_files = true;
|
||||
|
||||
std::wstring result;
|
||||
|
||||
// Create all supported .ext filter if more than one filter.
|
||||
if (file_ext.size() > 1) {
|
||||
std::set<base::WStringPiece> unique_exts;
|
||||
for (const auto& exts : file_ext) {
|
||||
for (const auto& ext : base::SplitStringPiece(
|
||||
exts, L";", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY)) {
|
||||
unique_exts.insert(ext);
|
||||
}
|
||||
}
|
||||
|
||||
if (unique_exts.size() > 1) {
|
||||
std::wstring ext;
|
||||
auto it = unique_exts.cbegin();
|
||||
ext = std::wstring(*it);
|
||||
for (++it; it != unique_exts.cend(); ++it) {
|
||||
ext += L";" + std::wstring(*it);
|
||||
}
|
||||
std::wstring desc =
|
||||
base::UTF16ToWide(l10n_util::GetStringUTF16(IDS_CUSTOM_FILES)) +
|
||||
L" (" + ext + L")";
|
||||
|
||||
result.append(desc.c_str(), desc.size() + 1); // Append NULL too.
|
||||
result.append(ext.c_str(), ext.size() + 1);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < file_ext.size(); ++i) {
|
||||
std::wstring ext = file_ext[i];
|
||||
std::wstring desc;
|
||||
if (i < ext_desc.size())
|
||||
desc = ext_desc[i];
|
||||
|
||||
if (ext.empty()) {
|
||||
// Force something reasonable to appear in the dialog box if there is no
|
||||
// extension provided.
|
||||
include_all_files = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (desc.empty()) {
|
||||
DCHECK(ext.find(L'.') != std::wstring::npos);
|
||||
std::wstring first_extension = ext.substr(ext.find(L'.'));
|
||||
size_t first_separator_index = first_extension.find(L';');
|
||||
if (first_separator_index != std::wstring::npos)
|
||||
first_extension = first_extension.substr(0, first_separator_index);
|
||||
|
||||
// Find the extension name without the preceeding '.' character.
|
||||
std::wstring ext_name = first_extension;
|
||||
size_t ext_index = ext_name.find_first_not_of(L'.');
|
||||
if (ext_index != std::wstring::npos)
|
||||
ext_name = ext_name.substr(ext_index);
|
||||
|
||||
if (!GetRegistryDescriptionFromExtension(first_extension, &desc)) {
|
||||
// The extension doesn't exist in the registry.
|
||||
include_all_files = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!desc.empty())
|
||||
desc += L" (" + ext + L")";
|
||||
else
|
||||
desc = ext;
|
||||
|
||||
result.append(desc.c_str(), desc.size() + 1); // Append NULL too.
|
||||
result.append(ext.c_str(), ext.size() + 1);
|
||||
}
|
||||
|
||||
if (include_all_files) {
|
||||
result.append(all_desc.c_str(), all_desc.size() + 1);
|
||||
result.append(all_ext.c_str(), all_ext.size() + 1);
|
||||
}
|
||||
|
||||
result.append(1, '\0'); // Double NULL required.
|
||||
return result;
|
||||
}
|
||||
|
||||
std::wstring GetDescriptionFromMimeType(const std::string& mime_type) {
|
||||
// Check for wild card mime types and return an appropriate description.
|
||||
static const struct {
|
||||
const char* mime_type;
|
||||
int string_id;
|
||||
} kWildCardMimeTypes[] = {
|
||||
{"audio", IDS_AUDIO_FILES},
|
||||
{"image", IDS_IMAGE_FILES},
|
||||
{"text", IDS_TEXT_FILES},
|
||||
{"video", IDS_VIDEO_FILES},
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < std::size(kWildCardMimeTypes); ++i) {
|
||||
if (mime_type == std::string(kWildCardMimeTypes[i].mime_type) + "/*") {
|
||||
return base::UTF16ToWide(
|
||||
l10n_util::GetStringUTF16(kWildCardMimeTypes[i].string_id));
|
||||
}
|
||||
}
|
||||
|
||||
return std::wstring();
|
||||
}
|
||||
|
||||
std::wstring GetFilterString(
|
||||
const std::vector<std::u16string>& accept_filters) {
|
||||
std::vector<std::wstring> extensions;
|
||||
std::vector<std::wstring> descriptions;
|
||||
|
||||
for (size_t i = 0; i < accept_filters.size(); ++i) {
|
||||
const std::wstring& filter = base::UTF16ToWide(accept_filters[i]);
|
||||
if (filter.empty())
|
||||
continue;
|
||||
|
||||
size_t sep_index = filter.find(L'|');
|
||||
if (sep_index != std::wstring::npos) {
|
||||
// Treat as a filter of the form "Filter Name|.ext1;.ext2;.ext3".
|
||||
const std::wstring& desc = filter.substr(0, sep_index);
|
||||
const std::vector<std::u16string>& ext = base::SplitString(
|
||||
base::WideToUTF16(filter.substr(sep_index + 1)), u";",
|
||||
base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
|
||||
std::wstring ext_str;
|
||||
for (size_t x = 0; x < ext.size(); ++x) {
|
||||
const std::wstring& file_ext = base::UTF16ToWide(ext[x]);
|
||||
if (!file_ext.empty() && file_ext[0] == L'.') {
|
||||
if (!ext_str.empty())
|
||||
ext_str += L";";
|
||||
ext_str += L"*" + file_ext;
|
||||
}
|
||||
}
|
||||
if (!ext_str.empty()) {
|
||||
extensions.push_back(ext_str);
|
||||
descriptions.push_back(desc);
|
||||
}
|
||||
} else if (filter[0] == L'.') {
|
||||
// Treat as an extension beginning with the '.' character.
|
||||
extensions.push_back(L"*" + filter);
|
||||
descriptions.push_back(std::wstring());
|
||||
} else {
|
||||
// Otherwise convert mime type to one or more extensions.
|
||||
const std::string& ascii = base::WideToASCII(filter);
|
||||
std::vector<base::FilePath::StringType> ext;
|
||||
std::wstring ext_str;
|
||||
net::GetExtensionsForMimeType(ascii, &ext);
|
||||
if (!ext.empty()) {
|
||||
for (size_t x = 0; x < ext.size(); ++x) {
|
||||
if (x != 0)
|
||||
ext_str += L";";
|
||||
ext_str += L"*." + ext[x];
|
||||
}
|
||||
extensions.push_back(ext_str);
|
||||
descriptions.push_back(GetDescriptionFromMimeType(ascii));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return FormatFilterForExtensions(extensions, descriptions, true);
|
||||
}
|
||||
|
||||
// From chrome/browser/views/shell_dialogs_win.cc
|
||||
|
||||
bool RunOpenFileDialog(const CefFileDialogRunner::FileChooserParams& params,
|
||||
HWND owner,
|
||||
int* filter_index,
|
||||
base::FilePath* path) {
|
||||
OPENFILENAME ofn;
|
||||
|
||||
// We must do this otherwise the ofn's FlagsEx may be initialized to random
|
||||
// junk in release builds which can cause the Places Bar not to show up!
|
||||
ZeroMemory(&ofn, sizeof(ofn));
|
||||
ofn.lStructSize = sizeof(ofn);
|
||||
ofn.hwndOwner = owner;
|
||||
|
||||
wchar_t filename[MAX_PATH] = {0};
|
||||
|
||||
ofn.lpstrFile = filename;
|
||||
ofn.nMaxFile = MAX_PATH;
|
||||
|
||||
std::wstring directory;
|
||||
if (!params.default_file_name.empty()) {
|
||||
if (params.default_file_name.EndsWithSeparator()) {
|
||||
// The value is only a directory.
|
||||
directory = params.default_file_name.value();
|
||||
} else {
|
||||
// The value is a file name and possibly a directory.
|
||||
base::wcslcpy(filename, params.default_file_name.value().c_str(),
|
||||
std::size(filename));
|
||||
directory = params.default_file_name.DirName().value();
|
||||
}
|
||||
}
|
||||
if (!directory.empty())
|
||||
ofn.lpstrInitialDir = directory.c_str();
|
||||
|
||||
std::wstring title;
|
||||
if (!params.title.empty()) {
|
||||
title = base::UTF16ToWide(params.title);
|
||||
} else {
|
||||
title = base::UTF16ToWide(
|
||||
l10n_util::GetStringUTF16(IDS_OPEN_FILE_DIALOG_TITLE));
|
||||
}
|
||||
if (!title.empty())
|
||||
ofn.lpstrTitle = title.c_str();
|
||||
|
||||
// We use OFN_NOCHANGEDIR so that the user can rename or delete the directory
|
||||
// without having to close Chrome first.
|
||||
ofn.Flags =
|
||||
OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR | OFN_EXPLORER | OFN_ENABLESIZING;
|
||||
if (params.hidereadonly)
|
||||
ofn.Flags |= OFN_HIDEREADONLY;
|
||||
|
||||
const std::wstring& filter = GetFilterString(params.accept_types);
|
||||
if (!filter.empty()) {
|
||||
ofn.lpstrFilter = filter.c_str();
|
||||
// Indices into |lpstrFilter| start at 1.
|
||||
ofn.nFilterIndex = *filter_index + 1;
|
||||
}
|
||||
|
||||
bool success = !!GetOpenFileName(&ofn);
|
||||
if (success) {
|
||||
*filter_index = ofn.nFilterIndex == 0 ? 0 : ofn.nFilterIndex - 1;
|
||||
*path = base::FilePath(filename);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
bool RunOpenMultiFileDialog(
|
||||
const CefFileDialogRunner::FileChooserParams& params,
|
||||
HWND owner,
|
||||
int* filter_index,
|
||||
std::vector<base::FilePath>* paths) {
|
||||
OPENFILENAME ofn;
|
||||
|
||||
// We must do this otherwise the ofn's FlagsEx may be initialized to random
|
||||
// junk in release builds which can cause the Places Bar not to show up!
|
||||
ZeroMemory(&ofn, sizeof(ofn));
|
||||
ofn.lStructSize = sizeof(ofn);
|
||||
ofn.hwndOwner = owner;
|
||||
|
||||
std::unique_ptr<wchar_t[]> filename(new wchar_t[UNICODE_STRING_MAX_CHARS]);
|
||||
filename[0] = 0;
|
||||
|
||||
ofn.lpstrFile = filename.get();
|
||||
ofn.nMaxFile = UNICODE_STRING_MAX_CHARS;
|
||||
|
||||
std::wstring directory;
|
||||
if (!params.default_file_name.empty()) {
|
||||
if (params.default_file_name.EndsWithSeparator()) {
|
||||
// The value is only a directory.
|
||||
directory = params.default_file_name.value();
|
||||
} else {
|
||||
// The value is a file name and possibly a directory.
|
||||
directory = params.default_file_name.DirName().value();
|
||||
}
|
||||
}
|
||||
if (!directory.empty())
|
||||
ofn.lpstrInitialDir = directory.c_str();
|
||||
|
||||
std::wstring title;
|
||||
if (!params.title.empty()) {
|
||||
title = base::UTF16ToWide(params.title);
|
||||
} else {
|
||||
title = base::UTF16ToWide(
|
||||
l10n_util::GetStringUTF16(IDS_OPEN_FILES_DIALOG_TITLE));
|
||||
}
|
||||
if (!title.empty())
|
||||
ofn.lpstrTitle = title.c_str();
|
||||
|
||||
// We use OFN_NOCHANGEDIR so that the user can rename or delete the directory
|
||||
// without having to close Chrome first.
|
||||
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_EXPLORER |
|
||||
OFN_ALLOWMULTISELECT | OFN_ENABLESIZING;
|
||||
if (params.hidereadonly)
|
||||
ofn.Flags |= OFN_HIDEREADONLY;
|
||||
|
||||
const std::wstring& filter = GetFilterString(params.accept_types);
|
||||
if (!filter.empty()) {
|
||||
ofn.lpstrFilter = filter.c_str();
|
||||
// Indices into |lpstrFilter| start at 1.
|
||||
ofn.nFilterIndex = *filter_index + 1;
|
||||
}
|
||||
|
||||
bool success = !!GetOpenFileName(&ofn);
|
||||
|
||||
if (success) {
|
||||
std::vector<base::FilePath> files;
|
||||
const wchar_t* selection = ofn.lpstrFile;
|
||||
while (*selection) { // Empty string indicates end of list.
|
||||
files.push_back(base::FilePath(selection));
|
||||
// Skip over filename and null-terminator.
|
||||
selection += files.back().value().length() + 1;
|
||||
}
|
||||
if (files.empty()) {
|
||||
success = false;
|
||||
} else if (files.size() == 1) {
|
||||
// When there is one file, it contains the path and filename.
|
||||
paths->swap(files);
|
||||
} else {
|
||||
// Otherwise, the first string is the path, and the remainder are
|
||||
// filenames.
|
||||
std::vector<base::FilePath>::iterator path = files.begin();
|
||||
for (std::vector<base::FilePath>::iterator file = path + 1;
|
||||
file != files.end(); ++file) {
|
||||
paths->push_back(path->Append(*file));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (success)
|
||||
*filter_index = ofn.nFilterIndex == 0 ? 0 : ofn.nFilterIndex - 1;
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
// The callback function for when the select folder dialog is opened.
|
||||
int CALLBACK BrowseCallbackProc(HWND window,
|
||||
UINT message,
|
||||
LPARAM parameter,
|
||||
LPARAM data) {
|
||||
if (message == BFFM_INITIALIZED) {
|
||||
// WParam is TRUE since passing a path.
|
||||
// data lParam member of the BROWSEINFO structure.
|
||||
SendMessage(window, BFFM_SETSELECTION, TRUE, (LPARAM)data);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool RunOpenFolderDialog(const CefFileDialogRunner::FileChooserParams& params,
|
||||
HWND owner,
|
||||
base::FilePath* path) {
|
||||
wchar_t dir_buffer[MAX_PATH + 1] = {0};
|
||||
|
||||
bool result = false;
|
||||
BROWSEINFO browse_info = {0};
|
||||
browse_info.hwndOwner = owner;
|
||||
browse_info.pszDisplayName = dir_buffer;
|
||||
browse_info.ulFlags = BIF_USENEWUI | BIF_RETURNONLYFSDIRS;
|
||||
|
||||
std::wstring title;
|
||||
if (!params.title.empty()) {
|
||||
title = base::UTF16ToWide(params.title);
|
||||
} else {
|
||||
title = base::UTF16ToWide(
|
||||
l10n_util::GetStringUTF16(IDS_SELECT_FOLDER_DIALOG_TITLE));
|
||||
}
|
||||
if (!title.empty())
|
||||
browse_info.lpszTitle = title.c_str();
|
||||
|
||||
const std::wstring& file_path = params.default_file_name.value();
|
||||
if (!file_path.empty()) {
|
||||
// Highlight the current value.
|
||||
browse_info.lParam = (LPARAM)file_path.c_str();
|
||||
browse_info.lpfn = &BrowseCallbackProc;
|
||||
}
|
||||
|
||||
LPITEMIDLIST list = SHBrowseForFolder(&browse_info);
|
||||
if (list) {
|
||||
STRRET out_dir_buffer;
|
||||
ZeroMemory(&out_dir_buffer, sizeof(out_dir_buffer));
|
||||
out_dir_buffer.uType = STRRET_WSTR;
|
||||
Microsoft::WRL::ComPtr<IShellFolder> shell_folder;
|
||||
if (SHGetDesktopFolder(shell_folder.GetAddressOf()) == NOERROR) {
|
||||
HRESULT hr = shell_folder->GetDisplayNameOf(list, SHGDN_FORPARSING,
|
||||
&out_dir_buffer);
|
||||
if (SUCCEEDED(hr) && out_dir_buffer.uType == STRRET_WSTR) {
|
||||
*path = base::FilePath(out_dir_buffer.pOleStr);
|
||||
CoTaskMemFree(out_dir_buffer.pOleStr);
|
||||
result = true;
|
||||
} else {
|
||||
// Use old way if we don't get what we want.
|
||||
wchar_t old_out_dir_buffer[MAX_PATH + 1];
|
||||
if (SHGetPathFromIDList(list, old_out_dir_buffer)) {
|
||||
*path = base::FilePath(old_out_dir_buffer);
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
CoTaskMemFree(list);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool RunSaveFileDialog(const CefFileDialogRunner::FileChooserParams& params,
|
||||
HWND owner,
|
||||
int* filter_index,
|
||||
base::FilePath* path) {
|
||||
OPENFILENAME ofn;
|
||||
|
||||
// We must do this otherwise the ofn's FlagsEx may be initialized to random
|
||||
// junk in release builds which can cause the Places Bar not to show up!
|
||||
ZeroMemory(&ofn, sizeof(ofn));
|
||||
ofn.lStructSize = sizeof(ofn);
|
||||
ofn.hwndOwner = owner;
|
||||
|
||||
wchar_t filename[MAX_PATH] = {0};
|
||||
|
||||
ofn.lpstrFile = filename;
|
||||
ofn.nMaxFile = MAX_PATH;
|
||||
|
||||
std::wstring directory;
|
||||
if (!params.default_file_name.empty()) {
|
||||
if (params.default_file_name.EndsWithSeparator()) {
|
||||
// The value is only a directory.
|
||||
directory = params.default_file_name.value();
|
||||
} else {
|
||||
// The value is a file name and possibly a directory.
|
||||
base::wcslcpy(filename, params.default_file_name.value().c_str(),
|
||||
std::size(filename));
|
||||
directory = params.default_file_name.DirName().value();
|
||||
}
|
||||
}
|
||||
if (!directory.empty())
|
||||
ofn.lpstrInitialDir = directory.c_str();
|
||||
|
||||
std::wstring title;
|
||||
if (!params.title.empty()) {
|
||||
title = base::UTF16ToWide(params.title);
|
||||
} else {
|
||||
title =
|
||||
base::UTF16ToWide(l10n_util::GetStringUTF16(IDS_SAVE_AS_DIALOG_TITLE));
|
||||
}
|
||||
if (!title.empty())
|
||||
ofn.lpstrTitle = title.c_str();
|
||||
|
||||
// We use OFN_NOCHANGEDIR so that the user can rename or delete the directory
|
||||
// without having to close Chrome first.
|
||||
ofn.Flags =
|
||||
OFN_EXPLORER | OFN_ENABLESIZING | OFN_NOCHANGEDIR | OFN_PATHMUSTEXIST;
|
||||
if (params.hidereadonly)
|
||||
ofn.Flags |= OFN_HIDEREADONLY;
|
||||
if (params.overwriteprompt)
|
||||
ofn.Flags |= OFN_OVERWRITEPROMPT;
|
||||
|
||||
const std::wstring& filter = GetFilterString(params.accept_types);
|
||||
if (!filter.empty()) {
|
||||
ofn.lpstrFilter = filter.c_str();
|
||||
// Indices into |lpstrFilter| start at 1.
|
||||
ofn.nFilterIndex = *filter_index + 1;
|
||||
// If a filter is specified and the default file name is changed then append
|
||||
// a file extension to the new name.
|
||||
ofn.lpstrDefExt = L"";
|
||||
}
|
||||
|
||||
bool success = !!GetSaveFileName(&ofn);
|
||||
if (success) {
|
||||
*filter_index = ofn.nFilterIndex == 0 ? 0 : ofn.nFilterIndex - 1;
|
||||
*path = base::FilePath(filename);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
CefFileDialogRunnerWin::CefFileDialogRunnerWin() {}
|
||||
|
||||
void CefFileDialogRunnerWin::Run(AlloyBrowserHostImpl* browser,
|
||||
const FileChooserParams& params,
|
||||
RunFileChooserCallback callback) {
|
||||
int filter_index = params.selected_accept_filter;
|
||||
std::vector<base::FilePath> files;
|
||||
|
||||
HWND owner = browser->GetWindowHandle();
|
||||
|
||||
if (params.mode == blink::mojom::FileChooserParams::Mode::kOpen) {
|
||||
base::FilePath file;
|
||||
if (RunOpenFileDialog(params, owner, &filter_index, &file))
|
||||
files.push_back(file);
|
||||
} else if (params.mode ==
|
||||
blink::mojom::FileChooserParams::Mode::kOpenMultiple) {
|
||||
RunOpenMultiFileDialog(params, owner, &filter_index, &files);
|
||||
} else if (params.mode ==
|
||||
blink::mojom::FileChooserParams::Mode::kUploadFolder) {
|
||||
base::FilePath file;
|
||||
if (RunOpenFolderDialog(params, owner, &file))
|
||||
files.push_back(file);
|
||||
} else if (params.mode == blink::mojom::FileChooserParams::Mode::kSave) {
|
||||
base::FilePath file;
|
||||
if (RunSaveFileDialog(params, owner, &filter_index, &file))
|
||||
files.push_back(file);
|
||||
} else {
|
||||
NOTIMPLEMENTED();
|
||||
}
|
||||
|
||||
std::move(callback).Run(filter_index, files);
|
||||
}
|
|
@ -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_
|
|
@ -194,11 +194,6 @@ CefEventHandle CefBrowserPlatformDelegateOsr::GetEventHandle(
|
|||
return native_delegate_->GetEventHandle(event);
|
||||
}
|
||||
|
||||
std::unique_ptr<CefFileDialogRunner>
|
||||
CefBrowserPlatformDelegateOsr::CreateFileDialogRunner() {
|
||||
return native_delegate_->CreateFileDialogRunner();
|
||||
}
|
||||
|
||||
std::unique_ptr<CefJavaScriptDialogRunner>
|
||||
CefBrowserPlatformDelegateOsr::CreateJavaScriptDialogRunner() {
|
||||
return native_delegate_->CreateJavaScriptDialogRunner();
|
||||
|
|
|
@ -49,7 +49,6 @@ class CefBrowserPlatformDelegateOsr
|
|||
const content::NativeWebKeyboardEvent& event) override;
|
||||
CefEventHandle GetEventHandle(
|
||||
const content::NativeWebKeyboardEvent& event) const override;
|
||||
std::unique_ptr<CefFileDialogRunner> CreateFileDialogRunner() override;
|
||||
std::unique_ptr<CefJavaScriptDialogRunner> CreateJavaScriptDialogRunner()
|
||||
override;
|
||||
std::unique_ptr<CefMenuRunner> CreateMenuRunner() override;
|
||||
|
|
|
@ -30,6 +30,33 @@ using content::BrowserThread;
|
|||
using printing::PageRanges;
|
||||
using printing::PrintSettings;
|
||||
|
||||
namespace {
|
||||
|
||||
printing::PrintingContextLinux::CreatePrintDialogFunctionPtr
|
||||
g_default_create_print_dialog_func = nullptr;
|
||||
printing::PrintingContextLinux::PdfPaperSizeFunctionPtr
|
||||
g_default_pdf_paper_size_func = nullptr;
|
||||
|
||||
CefRefPtr<CefBrowserHostBase> GetBrowserForContext(
|
||||
printing::PrintingContextLinux* context) {
|
||||
return extensions::GetOwnerBrowserForGlobalId(
|
||||
frame_util::MakeGlobalId(context->render_process_id(),
|
||||
context->render_frame_id()),
|
||||
nullptr);
|
||||
}
|
||||
|
||||
CefRefPtr<CefPrintHandler> GetPrintHandlerForBrowser(
|
||||
CefRefPtr<CefBrowserHostBase> browser) {
|
||||
if (browser) {
|
||||
if (auto client = browser->GetClient()) {
|
||||
return client->GetPrintHandler();
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
class CefPrintDialogCallbackImpl : public CefPrintDialogCallback {
|
||||
public:
|
||||
explicit CefPrintDialogCallbackImpl(CefRefPtr<CefPrintDialogLinux> dialog)
|
||||
|
@ -104,7 +131,30 @@ class CefPrintJobCallbackImpl : public CefPrintJobCallback {
|
|||
printing::PrintDialogGtkInterface* CefPrintDialogLinux::CreatePrintDialog(
|
||||
PrintingContextLinux* context) {
|
||||
CEF_REQUIRE_UIT();
|
||||
return new CefPrintDialogLinux(context);
|
||||
|
||||
printing::PrintDialogGtkInterface* interface = nullptr;
|
||||
|
||||
auto browser = GetBrowserForContext(context);
|
||||
if (!browser) {
|
||||
LOG(ERROR) << "No associated browser in CreatePrintDialog; using default "
|
||||
"printing implementation.";
|
||||
}
|
||||
|
||||
auto handler = GetPrintHandlerForBrowser(browser);
|
||||
if (!handler) {
|
||||
if (g_default_create_print_dialog_func) {
|
||||
interface = g_default_create_print_dialog_func(context);
|
||||
DCHECK(interface);
|
||||
}
|
||||
} else {
|
||||
interface = new CefPrintDialogLinux(context, browser, handler);
|
||||
}
|
||||
|
||||
if (!interface) {
|
||||
LOG(ERROR) << "Null interface in CreatePrintDialog; printing will fail.";
|
||||
}
|
||||
|
||||
return interface;
|
||||
}
|
||||
|
||||
// static
|
||||
|
@ -114,27 +164,42 @@ gfx::Size CefPrintDialogLinux::GetPdfPaperSize(
|
|||
|
||||
gfx::Size size;
|
||||
|
||||
auto browser = extensions::GetOwnerBrowserForGlobalId(
|
||||
frame_util::MakeGlobalId(context->render_process_id(),
|
||||
context->render_frame_id()),
|
||||
nullptr);
|
||||
DCHECK(browser);
|
||||
if (browser && browser->GetClient()) {
|
||||
if (auto handler = browser->GetClient()->GetPrintHandler()) {
|
||||
auto browser = GetBrowserForContext(context);
|
||||
if (!browser) {
|
||||
LOG(ERROR) << "No associated browser in GetPdfPaperSize; using default "
|
||||
"printing implementation.";
|
||||
}
|
||||
|
||||
auto handler = GetPrintHandlerForBrowser(browser);
|
||||
if (!handler) {
|
||||
if (g_default_pdf_paper_size_func) {
|
||||
size = g_default_pdf_paper_size_func(context);
|
||||
DCHECK(!size.IsEmpty());
|
||||
}
|
||||
} else {
|
||||
const printing::PrintSettings& settings = context->settings();
|
||||
CefSize cef_size = handler->GetPdfPaperSize(
|
||||
browser.get(), settings.device_units_per_inch());
|
||||
size.SetSize(cef_size.width, cef_size.height);
|
||||
}
|
||||
}
|
||||
|
||||
if (size.IsEmpty()) {
|
||||
LOG(ERROR) << "Empty size value returned in GetPdfPaperSize; "
|
||||
"PDF printing will fail.";
|
||||
LOG(ERROR) << "Empty size value returned in GetPdfPaperSize; PDF printing "
|
||||
"will fail.";
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
// static
|
||||
void CefPrintDialogLinux::SetDefaultPrintingContextFuncs(
|
||||
printing::PrintingContextLinux::CreatePrintDialogFunctionPtr
|
||||
create_print_dialog_func,
|
||||
printing::PrintingContextLinux::PdfPaperSizeFunctionPtr
|
||||
pdf_paper_size_func) {
|
||||
g_default_create_print_dialog_func = create_print_dialog_func;
|
||||
g_default_pdf_paper_size_func = pdf_paper_size_func;
|
||||
}
|
||||
|
||||
// static
|
||||
void CefPrintDialogLinux::OnPrintStart(CefRefPtr<CefBrowserHostBase> browser) {
|
||||
CEF_REQUIRE_UIT();
|
||||
|
@ -146,14 +211,13 @@ void CefPrintDialogLinux::OnPrintStart(CefRefPtr<CefBrowserHostBase> browser) {
|
|||
}
|
||||
}
|
||||
|
||||
CefPrintDialogLinux::CefPrintDialogLinux(PrintingContextLinux* context)
|
||||
: context_(context) {
|
||||
CefPrintDialogLinux::CefPrintDialogLinux(PrintingContextLinux* context,
|
||||
CefRefPtr<CefBrowserHostBase> browser,
|
||||
CefRefPtr<CefPrintHandler> handler)
|
||||
: context_(context), browser_(browser), handler_(handler) {
|
||||
DCHECK(context_);
|
||||
browser_ = extensions::GetOwnerBrowserForGlobalId(
|
||||
frame_util::MakeGlobalId(context_->render_process_id(),
|
||||
context_->render_frame_id()),
|
||||
nullptr);
|
||||
DCHECK(browser_);
|
||||
DCHECK(handler_);
|
||||
}
|
||||
|
||||
CefPrintDialogLinux::~CefPrintDialogLinux() {
|
||||
|
@ -161,7 +225,7 @@ CefPrintDialogLinux::~CefPrintDialogLinux() {
|
|||
// object because the PrintJobWorker which owns |context_| may already have
|
||||
// been deleted.
|
||||
CEF_REQUIRE_UIT();
|
||||
ReleaseHandler();
|
||||
handler_->OnPrintReset(browser_.get());
|
||||
}
|
||||
|
||||
void CefPrintDialogLinux::UseDefaultSettings() {
|
||||
|
@ -179,12 +243,6 @@ void CefPrintDialogLinux::ShowDialog(
|
|||
PrintingContextLinux::PrintSettingsCallback callback) {
|
||||
CEF_REQUIRE_UIT();
|
||||
|
||||
SetHandler();
|
||||
if (!handler_.get()) {
|
||||
std::move(callback).Run(printing::mojom::ResultCode::kCanceled);
|
||||
return;
|
||||
}
|
||||
|
||||
callback_ = std::move(callback);
|
||||
|
||||
CefRefPtr<CefPrintDialogCallbackImpl> callback_impl(
|
||||
|
@ -240,31 +298,11 @@ void CefPrintDialogLinux::ReleaseDialog() {
|
|||
Release();
|
||||
}
|
||||
|
||||
void CefPrintDialogLinux::SetHandler() {
|
||||
if (handler_.get())
|
||||
return;
|
||||
|
||||
if (browser_ && browser_->GetClient()) {
|
||||
handler_ = browser_->GetClient()->GetPrintHandler();
|
||||
}
|
||||
}
|
||||
|
||||
void CefPrintDialogLinux::ReleaseHandler() {
|
||||
if (handler_.get()) {
|
||||
handler_->OnPrintReset(browser_.get());
|
||||
handler_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool CefPrintDialogLinux::UpdateSettings(
|
||||
std::unique_ptr<PrintSettings> settings,
|
||||
bool get_defaults) {
|
||||
CEF_REQUIRE_UIT();
|
||||
|
||||
SetHandler();
|
||||
if (!handler_.get())
|
||||
return false;
|
||||
|
||||
CefRefPtr<CefPrintSettingsImpl> settings_impl(
|
||||
new CefPrintSettingsImpl(std::move(settings), false));
|
||||
handler_->OnPrintSettings(browser_.get(), settings_impl.get(), get_defaults);
|
||||
|
|
|
@ -39,6 +39,13 @@ class CefPrintDialogLinux : public printing::PrintDialogGtkInterface,
|
|||
// Returns the paper size in device units.
|
||||
static gfx::Size GetPdfPaperSize(printing::PrintingContextLinux* context);
|
||||
|
||||
// Used for calling into the default GTK implementation.
|
||||
static void SetDefaultPrintingContextFuncs(
|
||||
printing::PrintingContextLinux::CreatePrintDialogFunctionPtr
|
||||
create_print_dialog_func,
|
||||
printing::PrintingContextLinux::PdfPaperSizeFunctionPtr
|
||||
pdf_paper_size_func);
|
||||
|
||||
// Notify the client when printing has started.
|
||||
static void OnPrintStart(CefRefPtr<CefBrowserHostBase> browser);
|
||||
|
||||
|
@ -65,12 +72,11 @@ class CefPrintDialogLinux : public printing::PrintDialogGtkInterface,
|
|||
friend class CefPrintDialogCallbackImpl;
|
||||
friend class CefPrintJobCallbackImpl;
|
||||
|
||||
explicit CefPrintDialogLinux(PrintingContextLinux* context);
|
||||
CefPrintDialogLinux(PrintingContextLinux* context,
|
||||
CefRefPtr<CefBrowserHostBase> browser,
|
||||
CefRefPtr<CefPrintHandler> handler);
|
||||
~CefPrintDialogLinux() override;
|
||||
|
||||
void SetHandler();
|
||||
void ReleaseHandler();
|
||||
|
||||
bool UpdateSettings(std::unique_ptr<printing::PrintSettings> settings,
|
||||
bool get_defaults);
|
||||
|
||||
|
@ -84,12 +90,12 @@ class CefPrintDialogLinux : public printing::PrintDialogGtkInterface,
|
|||
// Handles print job response.
|
||||
void OnJobCompleted();
|
||||
|
||||
CefRefPtr<CefPrintHandler> handler_;
|
||||
|
||||
// Printing dialog callback.
|
||||
PrintingContextLinux::PrintSettingsCallback callback_;
|
||||
|
||||
PrintingContextLinux* context_;
|
||||
CefRefPtr<CefBrowserHostBase> browser_;
|
||||
CefRefPtr<CefPrintHandler> handler_;
|
||||
|
||||
base::FilePath path_to_pdf_;
|
||||
};
|
||||
|
|
|
@ -257,11 +257,6 @@ CefEventHandle CefBrowserPlatformDelegateViews::GetEventHandle(
|
|||
return native_delegate_->GetEventHandle(event);
|
||||
}
|
||||
|
||||
std::unique_ptr<CefFileDialogRunner>
|
||||
CefBrowserPlatformDelegateViews::CreateFileDialogRunner() {
|
||||
return native_delegate_->CreateFileDialogRunner();
|
||||
}
|
||||
|
||||
std::unique_ptr<CefJavaScriptDialogRunner>
|
||||
CefBrowserPlatformDelegateViews::CreateJavaScriptDialogRunner() {
|
||||
return native_delegate_->CreateJavaScriptDialogRunner();
|
||||
|
|
|
@ -60,7 +60,6 @@ class CefBrowserPlatformDelegateViews
|
|||
const content::NativeWebKeyboardEvent& event) override;
|
||||
CefEventHandle GetEventHandle(
|
||||
const content::NativeWebKeyboardEvent& event) const override;
|
||||
std::unique_ptr<CefFileDialogRunner> CreateFileDialogRunner() override;
|
||||
std::unique_ptr<CefJavaScriptDialogRunner> CreateJavaScriptDialogRunner()
|
||||
override;
|
||||
std::unique_ptr<CefMenuRunner> CreateMenuRunner() override;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
// implementations. See the translator.README.txt file in the tools directory
|
||||
// for more information.
|
||||
//
|
||||
// $hash=2edab12ab1759213ab9a6b7620ea39a74291abc7$
|
||||
// $hash=fa3208182bcdb9aab36096b3ce5ecdd35cb0a80f$
|
||||
//
|
||||
|
||||
#include "libcef_dll/ctocpp/browser_host_ctocpp.h"
|
||||
|
@ -261,7 +261,6 @@ void CefBrowserHostCToCpp::RunFileDialog(
|
|||
const CefString& title,
|
||||
const CefString& default_file_path,
|
||||
const std::vector<CefString>& accept_filters,
|
||||
int selected_accept_filter,
|
||||
CefRefPtr<CefRunFileDialogCallback> callback) {
|
||||
shutdown_checker::AssertNotShutdown();
|
||||
|
||||
|
@ -271,10 +270,6 @@ void CefBrowserHostCToCpp::RunFileDialog(
|
|||
|
||||
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
|
||||
|
||||
// Verify param: selected_accept_filter; type: simple_byval
|
||||
DCHECK_GE(selected_accept_filter, 0);
|
||||
if (selected_accept_filter < 0)
|
||||
return;
|
||||
// Verify param: callback; type: refptr_diff
|
||||
DCHECK(callback.get());
|
||||
if (!callback.get())
|
||||
|
@ -290,7 +285,6 @@ void CefBrowserHostCToCpp::RunFileDialog(
|
|||
// Execute
|
||||
_struct->run_file_dialog(_struct, mode, title.GetStruct(),
|
||||
default_file_path.GetStruct(), accept_filtersList,
|
||||
selected_accept_filter,
|
||||
CefRunFileDialogCallbackCppToC::Wrap(callback));
|
||||
|
||||
// Restore param:accept_filters; type: string_vec_byref_const
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
// implementations. See the translator.README.txt file in the tools directory
|
||||
// for more information.
|
||||
//
|
||||
// $hash=6de4205143b6855e7ccf54da14a0494db0b4aaa3$
|
||||
// $hash=e82e7bf06a027262268172fd74254a8af087e528$
|
||||
//
|
||||
|
||||
#ifndef CEF_LIBCEF_DLL_CTOCPP_BROWSER_HOST_CTOCPP_H_
|
||||
|
@ -52,7 +52,6 @@ class CefBrowserHostCToCpp : public CefCToCppRefCounted<CefBrowserHostCToCpp,
|
|||
const CefString& title,
|
||||
const CefString& default_file_path,
|
||||
const std::vector<CefString>& accept_filters,
|
||||
int selected_accept_filter,
|
||||
CefRefPtr<CefRunFileDialogCallback> callback) override;
|
||||
void StartDownload(const CefString& url) override;
|
||||
void DownloadImage(const CefString& image_url,
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
// implementations. See the translator.README.txt file in the tools directory
|
||||
// for more information.
|
||||
//
|
||||
// $hash=cac933371fc47c864230d4537ef1da76cd7e4d8e$
|
||||
// $hash=336c57e3c57a1a5bf8fa4a39aee8f204788ccddb$
|
||||
//
|
||||
|
||||
#include "libcef_dll/ctocpp/dialog_handler_ctocpp.h"
|
||||
|
@ -27,7 +27,6 @@ bool CefDialogHandlerCToCpp::OnFileDialog(
|
|||
const CefString& title,
|
||||
const CefString& default_file_path,
|
||||
const std::vector<CefString>& accept_filters,
|
||||
int selected_accept_filter,
|
||||
CefRefPtr<CefFileDialogCallback> callback) {
|
||||
shutdown_checker::AssertNotShutdown();
|
||||
|
||||
|
@ -41,10 +40,6 @@ bool CefDialogHandlerCToCpp::OnFileDialog(
|
|||
DCHECK(browser.get());
|
||||
if (!browser.get())
|
||||
return false;
|
||||
// Verify param: selected_accept_filter; type: simple_byval
|
||||
DCHECK_GE(selected_accept_filter, 0);
|
||||
if (selected_accept_filter < 0)
|
||||
return false;
|
||||
// Verify param: callback; type: refptr_diff
|
||||
DCHECK(callback.get());
|
||||
if (!callback.get())
|
||||
|
@ -60,7 +55,7 @@ bool CefDialogHandlerCToCpp::OnFileDialog(
|
|||
// Execute
|
||||
int _retval = _struct->on_file_dialog(
|
||||
_struct, CefBrowserCppToC::Wrap(browser), mode, title.GetStruct(),
|
||||
default_file_path.GetStruct(), accept_filtersList, selected_accept_filter,
|
||||
default_file_path.GetStruct(), accept_filtersList,
|
||||
CefFileDialogCallbackCppToC::Wrap(callback));
|
||||
|
||||
// Restore param:accept_filters; type: string_vec_byref_const
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
// implementations. See the translator.README.txt file in the tools directory
|
||||
// for more information.
|
||||
//
|
||||
// $hash=4c07a40d3bd171adf3ae3cc4aa935bc7eca4aa5e$
|
||||
// $hash=1577adae508ad046bb2c7786f040ccc599087b8d$
|
||||
//
|
||||
|
||||
#ifndef CEF_LIBCEF_DLL_CTOCPP_DIALOG_HANDLER_CTOCPP_H_
|
||||
|
@ -41,7 +41,6 @@ class CefDialogHandlerCToCpp
|
|||
const CefString& title,
|
||||
const CefString& default_file_path,
|
||||
const std::vector<CefString>& accept_filters,
|
||||
int selected_accept_filter,
|
||||
CefRefPtr<CefFileDialogCallback> callback) override;
|
||||
};
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
// implementations. See the translator.README.txt file in the tools directory
|
||||
// for more information.
|
||||
//
|
||||
// $hash=8fecb808fb6a84d630d1e8c5380a5ffd900b3654$
|
||||
// $hash=9fb143d4df823ed6a7dfca295ce4ca2b5756df9c$
|
||||
//
|
||||
|
||||
#include "libcef_dll/ctocpp/file_dialog_callback_ctocpp.h"
|
||||
|
@ -20,7 +20,6 @@
|
|||
|
||||
NO_SANITIZE("cfi-icall")
|
||||
void CefFileDialogCallbackCToCpp::Continue(
|
||||
int selected_accept_filter,
|
||||
const std::vector<CefString>& file_paths) {
|
||||
shutdown_checker::AssertNotShutdown();
|
||||
|
||||
|
@ -30,10 +29,6 @@ void CefFileDialogCallbackCToCpp::Continue(
|
|||
|
||||
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
|
||||
|
||||
// Verify param: selected_accept_filter; type: simple_byval
|
||||
DCHECK_GE(selected_accept_filter, 0);
|
||||
if (selected_accept_filter < 0)
|
||||
return;
|
||||
// Unverified params: file_paths
|
||||
|
||||
// Translate param: file_paths; type: string_vec_byref_const
|
||||
|
@ -43,7 +38,7 @@ void CefFileDialogCallbackCToCpp::Continue(
|
|||
transfer_string_list_contents(file_paths, file_pathsList);
|
||||
|
||||
// Execute
|
||||
_struct->cont(_struct, selected_accept_filter, file_pathsList);
|
||||
_struct->cont(_struct, file_pathsList);
|
||||
|
||||
// Restore param:file_paths; type: string_vec_byref_const
|
||||
if (file_pathsList)
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
// implementations. See the translator.README.txt file in the tools directory
|
||||
// for more information.
|
||||
//
|
||||
// $hash=d84ac439b3372160aa3886b28b3ff81e49f05a6d$
|
||||
// $hash=acb14970579704b71425d23b2bb7468f782a1e17$
|
||||
//
|
||||
|
||||
#ifndef CEF_LIBCEF_DLL_CTOCPP_FILE_DIALOG_CALLBACK_CTOCPP_H_
|
||||
|
@ -36,8 +36,7 @@ class CefFileDialogCallbackCToCpp
|
|||
virtual ~CefFileDialogCallbackCToCpp();
|
||||
|
||||
// CefFileDialogCallback methods.
|
||||
void Continue(int selected_accept_filter,
|
||||
const std::vector<CefString>& file_paths) override;
|
||||
void Continue(const std::vector<CefString>& file_paths) override;
|
||||
void Cancel() override;
|
||||
};
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
// implementations. See the translator.README.txt file in the tools directory
|
||||
// for more information.
|
||||
//
|
||||
// $hash=cb29585261ed25ddd2ee1b4b5c890565e72e5d22$
|
||||
// $hash=ef632f8846499c0605300240a2ec7240a1750ce2$
|
||||
//
|
||||
|
||||
#include "libcef_dll/ctocpp/run_file_dialog_callback_ctocpp.h"
|
||||
|
@ -20,7 +20,6 @@
|
|||
|
||||
NO_SANITIZE("cfi-icall")
|
||||
void CefRunFileDialogCallbackCToCpp::OnFileDialogDismissed(
|
||||
int selected_accept_filter,
|
||||
const std::vector<CefString>& file_paths) {
|
||||
shutdown_checker::AssertNotShutdown();
|
||||
|
||||
|
@ -30,10 +29,6 @@ void CefRunFileDialogCallbackCToCpp::OnFileDialogDismissed(
|
|||
|
||||
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
|
||||
|
||||
// Verify param: selected_accept_filter; type: simple_byval
|
||||
DCHECK_GE(selected_accept_filter, 0);
|
||||
if (selected_accept_filter < 0)
|
||||
return;
|
||||
// Unverified params: file_paths
|
||||
|
||||
// Translate param: file_paths; type: string_vec_byref_const
|
||||
|
@ -43,8 +38,7 @@ void CefRunFileDialogCallbackCToCpp::OnFileDialogDismissed(
|
|||
transfer_string_list_contents(file_paths, file_pathsList);
|
||||
|
||||
// Execute
|
||||
_struct->on_file_dialog_dismissed(_struct, selected_accept_filter,
|
||||
file_pathsList);
|
||||
_struct->on_file_dialog_dismissed(_struct, file_pathsList);
|
||||
|
||||
// Restore param:file_paths; type: string_vec_byref_const
|
||||
if (file_pathsList)
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
// implementations. See the translator.README.txt file in the tools directory
|
||||
// for more information.
|
||||
//
|
||||
// $hash=63d2d1da715395296899acc4ed165cf7dae4d78c$
|
||||
// $hash=12c1546549e1b0d29beb91241361581f3e3da67f$
|
||||
//
|
||||
|
||||
#ifndef CEF_LIBCEF_DLL_CTOCPP_RUN_FILE_DIALOG_CALLBACK_CTOCPP_H_
|
||||
|
@ -38,8 +38,7 @@ class CefRunFileDialogCallbackCToCpp
|
|||
virtual ~CefRunFileDialogCallbackCToCpp();
|
||||
|
||||
// CefRunFileDialogCallback methods.
|
||||
void OnFileDialogDismissed(int selected_accept_filter,
|
||||
const std::vector<CefString>& file_paths) override;
|
||||
void OnFileDialogDismissed(const std::vector<CefString>& file_paths) override;
|
||||
};
|
||||
|
||||
#endif // CEF_LIBCEF_DLL_CTOCPP_RUN_FILE_DIALOG_CALLBACK_CTOCPP_H_
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1,400 @@
|
|||
diff --git chrome/browser/file_select_helper.cc chrome/browser/file_select_helper.cc
|
||||
index 8792cc3a5d40e..8807feaf6063c 100644
|
||||
--- chrome/browser/file_select_helper.cc
|
||||
+++ chrome/browser/file_select_helper.cc
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "base/threading/hang_watcher.h"
|
||||
#include "build/build_config.h"
|
||||
#include "build/chromeos_buildflags.h"
|
||||
+#include "cef/libcef/features/runtime.h"
|
||||
#include "chrome/browser/browser_process.h"
|
||||
#include "chrome/browser/enterprise/connectors/common.h"
|
||||
#include "chrome/browser/platform_util.h"
|
||||
@@ -254,6 +255,13 @@ void FileSelectHelper::OnListFile(
|
||||
void FileSelectHelper::LaunchConfirmationDialog(
|
||||
const base::FilePath& path,
|
||||
std::vector<ui::SelectedFileInfo> selected_files) {
|
||||
+ if (cef::IsAlloyRuntimeEnabled() || run_from_cef_) {
|
||||
+ // Don't show the upload confirmation dialog with the Alloy runtime, or
|
||||
+ // when triggered via CEF (initially or recursively).
|
||||
+ ConvertToFileChooserFileInfoList(selected_files);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
ShowFolderUploadConfirmationDialog(
|
||||
path,
|
||||
base::BindOnce(&FileSelectHelper::ConvertToFileChooserFileInfoList, this),
|
||||
@@ -450,7 +458,8 @@ void FileSelectHelper::DontAbortOnMissingWebContentsForTesting() {
|
||||
|
||||
std::unique_ptr<ui::SelectFileDialog::FileTypeInfo>
|
||||
FileSelectHelper::GetFileTypesFromAcceptType(
|
||||
- const std::vector<std::u16string>& accept_types) {
|
||||
+ const std::vector<std::u16string>& accept_types,
|
||||
+ bool run_from_cef) {
|
||||
std::unique_ptr<ui::SelectFileDialog::FileTypeInfo> base_file_type(
|
||||
new ui::SelectFileDialog::FileTypeInfo());
|
||||
if (accept_types.empty())
|
||||
@@ -464,17 +473,24 @@ FileSelectHelper::GetFileTypesFromAcceptType(
|
||||
std::vector<base::FilePath::StringType>* extensions =
|
||||
&file_type->extensions.back();
|
||||
|
||||
+ // Create individual filters for each accept type.
|
||||
+ std::vector<std::vector<base::FilePath::StringType>> all_extensions;
|
||||
+ std::vector<std::u16string> all_overrides;
|
||||
+
|
||||
// Find the corresponding extensions.
|
||||
int valid_type_count = 0;
|
||||
int description_id = 0;
|
||||
for (const auto& accept_type : accept_types) {
|
||||
+ std::vector<base::FilePath::StringType> current_extensions;
|
||||
+ description_id = 0;
|
||||
+
|
||||
size_t old_extension_size = extensions->size();
|
||||
if (accept_type[0] == '.') {
|
||||
// If the type starts with a period it is assumed to be a file extension
|
||||
// so we just have to add it to the list.
|
||||
base::FilePath::StringType ext =
|
||||
base::FilePath::FromUTF16Unsafe(accept_type).value();
|
||||
- extensions->push_back(ext.substr(1));
|
||||
+ current_extensions.push_back(ext.substr(1));
|
||||
} else {
|
||||
if (!base::IsStringASCII(accept_type))
|
||||
continue;
|
||||
@@ -485,10 +501,18 @@ FileSelectHelper::GetFileTypesFromAcceptType(
|
||||
description_id = IDS_AUDIO_FILES;
|
||||
else if (ascii_type == "video/*")
|
||||
description_id = IDS_VIDEO_FILES;
|
||||
-
|
||||
- net::GetExtensionsForMimeType(ascii_type, extensions);
|
||||
+ net::GetExtensionsForMimeType(ascii_type, ¤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<content::FileSelectListener> listener,
|
||||
- const FileChooserParams& params) {
|
||||
+ const FileChooserParams& params,
|
||||
+ bool run_from_cef) {
|
||||
Profile* profile = Profile::FromBrowserContext(
|
||||
render_frame_host->GetProcess()->GetBrowserContext());
|
||||
|
||||
@@ -539,6 +573,7 @@ void FileSelectHelper::RunFileChooser(
|
||||
// message.
|
||||
scoped_refptr<FileSelectHelper> file_select_helper(
|
||||
new FileSelectHelper(profile));
|
||||
+ file_select_helper->run_from_cef_ = run_from_cef;
|
||||
file_select_helper->RunFileChooser(render_frame_host, std::move(listener),
|
||||
params.Clone());
|
||||
}
|
||||
@@ -592,7 +627,8 @@ void FileSelectHelper::RunFileChooser(
|
||||
}
|
||||
|
||||
void FileSelectHelper::GetFileTypesInThreadPool(FileChooserParamsPtr params) {
|
||||
- select_file_types_ = GetFileTypesFromAcceptType(params->accept_types);
|
||||
+ select_file_types_ = GetFileTypesFromAcceptType(params->accept_types,
|
||||
+ run_from_cef_);
|
||||
select_file_types_->allowed_paths =
|
||||
params->need_local_path ? ui::SelectFileDialog::FileTypeInfo::NATIVE_PATH
|
||||
: ui::SelectFileDialog::FileTypeInfo::ANY_PATH;
|
||||
diff --git chrome/browser/file_select_helper.h chrome/browser/file_select_helper.h
|
||||
index f9d1f31b36357..122e1ce9fa962 100644
|
||||
--- chrome/browser/file_select_helper.h
|
||||
+++ chrome/browser/file_select_helper.h
|
||||
@@ -59,7 +59,8 @@ class FileSelectHelper : public base::RefCountedThreadSafe<
|
||||
static void RunFileChooser(
|
||||
content::RenderFrameHost* render_frame_host,
|
||||
scoped_refptr<content::FileSelectListener> listener,
|
||||
- const blink::mojom::FileChooserParams& params);
|
||||
+ const blink::mojom::FileChooserParams& params,
|
||||
+ bool run_from_cef = false);
|
||||
|
||||
// Enumerates all the files in directory.
|
||||
static void EnumerateDirectory(
|
||||
@@ -255,7 +256,8 @@ class FileSelectHelper : public base::RefCountedThreadSafe<
|
||||
// |accept_types| contains only valid lowercased MIME types or file extensions
|
||||
// beginning with a period (.).
|
||||
static std::unique_ptr<ui::SelectFileDialog::FileTypeInfo>
|
||||
- GetFileTypesFromAcceptType(const std::vector<std::u16string>& accept_types);
|
||||
+ GetFileTypesFromAcceptType(const std::vector<std::u16string>& accept_types,
|
||||
+ bool run_from_cef);
|
||||
|
||||
// Check the accept type is valid. It is expected to be all lower case with
|
||||
// no whitespace.
|
||||
@@ -319,6 +321,9 @@ class FileSelectHelper : public base::RefCountedThreadSafe<
|
||||
|
||||
// Set to false in unit tests since there is no WebContents.
|
||||
bool abort_on_missing_web_contents_in_tests_ = true;
|
||||
+
|
||||
+ // Set to true if this dialog was triggered via CEF.
|
||||
+ bool run_from_cef_ = false;
|
||||
};
|
||||
|
||||
#endif // CHROME_BROWSER_FILE_SELECT_HELPER_H_
|
||||
diff --git chrome/browser/ui/chrome_select_file_policy.h chrome/browser/ui/chrome_select_file_policy.h
|
||||
index 2cf473c35b67a..e3552bd0f17d4 100644
|
||||
--- chrome/browser/ui/chrome_select_file_policy.h
|
||||
+++ chrome/browser/ui/chrome_select_file_policy.h
|
||||
@@ -30,6 +30,8 @@ class ChromeSelectFilePolicy : public ui::SelectFilePolicy {
|
||||
// Returns true if local state allows showing file pickers.
|
||||
static bool FileSelectDialogsAllowed();
|
||||
|
||||
+ content::WebContents* source_contents() const { return source_contents_; }
|
||||
+
|
||||
private:
|
||||
raw_ptr<content::WebContents> source_contents_;
|
||||
};
|
||||
diff --git printing/printing_context_linux.cc printing/printing_context_linux.cc
|
||||
index 204cec8311bec..b2d7e16614e15 100644
|
||||
--- printing/printing_context_linux.cc
|
||||
+++ printing/printing_context_linux.cc
|
||||
@@ -54,20 +54,23 @@ PrintingContextLinux::~PrintingContextLinux() {
|
||||
}
|
||||
|
||||
// static
|
||||
-void PrintingContextLinux::SetCreatePrintDialogFunction(
|
||||
- PrintDialogGtkInterface* (*create_dialog_func)(
|
||||
- PrintingContextLinux* context)) {
|
||||
+PrintingContextLinux::CreatePrintDialogFunctionPtr
|
||||
+PrintingContextLinux::SetCreatePrintDialogFunction(
|
||||
+ CreatePrintDialogFunctionPtr create_dialog_func) {
|
||||
DCHECK(create_dialog_func);
|
||||
- DCHECK(!create_dialog_func_);
|
||||
+ auto old_func = create_dialog_func_;
|
||||
create_dialog_func_ = create_dialog_func;
|
||||
+ return old_func;
|
||||
}
|
||||
|
||||
// static
|
||||
-void PrintingContextLinux::SetPdfPaperSizeFunction(
|
||||
- gfx::Size (*get_pdf_paper_size)(PrintingContextLinux* context)) {
|
||||
+PrintingContextLinux::PdfPaperSizeFunctionPtr
|
||||
+PrintingContextLinux::SetPdfPaperSizeFunction(
|
||||
+ PdfPaperSizeFunctionPtr get_pdf_paper_size) {
|
||||
DCHECK(get_pdf_paper_size);
|
||||
- DCHECK(!get_pdf_paper_size_);
|
||||
+ auto old_func = get_pdf_paper_size_;
|
||||
get_pdf_paper_size_ = get_pdf_paper_size;
|
||||
+ return old_func;
|
||||
}
|
||||
|
||||
void PrintingContextLinux::AskUserForSettings(int max_pages,
|
||||
diff --git printing/printing_context_linux.h printing/printing_context_linux.h
|
||||
index 653170ba60e83..677df89f93e8d 100644
|
||||
--- printing/printing_context_linux.h
|
||||
+++ printing/printing_context_linux.h
|
||||
@@ -25,12 +25,17 @@ class COMPONENT_EXPORT(PRINTING) PrintingContextLinux : public PrintingContext {
|
||||
~PrintingContextLinux() override;
|
||||
|
||||
// Sets the function that creates the print dialog.
|
||||
- static void SetCreatePrintDialogFunction(PrintDialogGtkInterface* (
|
||||
- *create_dialog_func)(PrintingContextLinux* context));
|
||||
+ // Returns the old function, if any.
|
||||
+ using CreatePrintDialogFunctionPtr =
|
||||
+ PrintDialogGtkInterface* (*)(PrintingContextLinux* context);
|
||||
+ static CreatePrintDialogFunctionPtr SetCreatePrintDialogFunction(
|
||||
+ CreatePrintDialogFunctionPtr);
|
||||
|
||||
// Sets the function that returns pdf paper size through the native API.
|
||||
- static void SetPdfPaperSizeFunction(
|
||||
- gfx::Size (*get_pdf_paper_size)(PrintingContextLinux* context));
|
||||
+ // Returns the old function, if any.
|
||||
+ using PdfPaperSizeFunctionPtr = gfx::Size (*)(PrintingContextLinux* context);
|
||||
+ static PdfPaperSizeFunctionPtr SetPdfPaperSizeFunction(
|
||||
+ PdfPaperSizeFunctionPtr);
|
||||
|
||||
// Initializes with predefined settings.
|
||||
void InitWithSettings(std::unique_ptr<PrintSettings> settings);
|
||||
diff --git ui/shell_dialogs/execute_select_file_win.cc ui/shell_dialogs/execute_select_file_win.cc
|
||||
index 063d4c7c96cba..24bd0533af65b 100644
|
||||
--- ui/shell_dialogs/execute_select_file_win.cc
|
||||
+++ ui/shell_dialogs/execute_select_file_win.cc
|
||||
@@ -289,9 +289,7 @@ bool ExecuteSelectSingleFile(HWND owner,
|
||||
const std::vector<FileFilterSpec>& filter,
|
||||
int* filter_index,
|
||||
std::vector<base::FilePath>* paths) {
|
||||
- // Note: The title is not passed down for historical reasons.
|
||||
- // TODO(pmonette): Figure out if it's a worthwhile improvement.
|
||||
- return RunOpenFileDialog(owner, std::u16string(), std::u16string(),
|
||||
+ return RunOpenFileDialog(owner, title, std::u16string(),
|
||||
default_path, filter, 0, filter_index, paths);
|
||||
}
|
||||
|
||||
@@ -303,14 +301,13 @@ bool ExecuteSelectMultipleFile(HWND owner,
|
||||
std::vector<base::FilePath>* paths) {
|
||||
DWORD dialog_options = FOS_ALLOWMULTISELECT;
|
||||
|
||||
- // Note: The title is not passed down for historical reasons.
|
||||
- // TODO(pmonette): Figure out if it's a worthwhile improvement.
|
||||
- return RunOpenFileDialog(owner, std::u16string(), std::u16string(),
|
||||
+ return RunOpenFileDialog(owner, title, std::u16string(),
|
||||
default_path, filter, dialog_options, filter_index,
|
||||
paths);
|
||||
}
|
||||
|
||||
bool ExecuteSaveFile(HWND owner,
|
||||
+ const std::u16string& title,
|
||||
const base::FilePath& default_path,
|
||||
const std::vector<FileFilterSpec>& filter,
|
||||
const std::wstring& def_ext,
|
||||
@@ -323,9 +320,7 @@ bool ExecuteSaveFile(HWND owner,
|
||||
|
||||
DWORD dialog_options = FOS_OVERWRITEPROMPT;
|
||||
|
||||
- // Note: The title is not passed down for historical reasons.
|
||||
- // TODO(pmonette): Figure out if it's a worthwhile improvement.
|
||||
- return RunSaveFileDialog(owner, std::u16string(), default_path, filter,
|
||||
+ return RunSaveFileDialog(owner, title, default_path, filter,
|
||||
dialog_options, def_ext, filter_index, path);
|
||||
}
|
||||
|
||||
@@ -390,7 +385,7 @@ void ExecuteSelectFile(
|
||||
break;
|
||||
case SelectFileDialog::SELECT_SAVEAS_FILE: {
|
||||
base::FilePath path;
|
||||
- if (ExecuteSaveFile(owner, default_path, filter, default_extension,
|
||||
+ if (ExecuteSaveFile(owner, title, default_path, filter, default_extension,
|
||||
&file_type_index, &path)) {
|
||||
paths.push_back(std::move(path));
|
||||
}
|
||||
diff --git ui/shell_dialogs/select_file_dialog.cc ui/shell_dialogs/select_file_dialog.cc
|
||||
index a622d465ab9e9..b5c11c3117738 100644
|
||||
--- ui/shell_dialogs/select_file_dialog.cc
|
||||
+++ ui/shell_dialogs/select_file_dialog.cc
|
||||
@@ -64,8 +64,10 @@ void SelectFileDialog::SetFactory(ui::SelectFileDialogFactory* factory) {
|
||||
// static
|
||||
scoped_refptr<SelectFileDialog> SelectFileDialog::Create(
|
||||
Listener* listener,
|
||||
- std::unique_ptr<ui::SelectFilePolicy> policy) {
|
||||
- if (dialog_factory_)
|
||||
+ std::unique_ptr<ui::SelectFilePolicy> policy,
|
||||
+ bool run_from_cef) {
|
||||
+ // Avoid reentrancy of the CEF factory.
|
||||
+ if (dialog_factory_ && (!run_from_cef || !dialog_factory_->IsCefFactory()))
|
||||
return dialog_factory_->Create(listener, std::move(policy));
|
||||
return CreateSelectFileDialog(listener, std::move(policy));
|
||||
}
|
||||
diff --git ui/shell_dialogs/select_file_dialog.h ui/shell_dialogs/select_file_dialog.h
|
||||
index 8a417fc43a7e4..6d7b065b5b192 100644
|
||||
--- ui/shell_dialogs/select_file_dialog.h
|
||||
+++ ui/shell_dialogs/select_file_dialog.h
|
||||
@@ -111,7 +111,8 @@ class SHELL_DIALOGS_EXPORT SelectFileDialog
|
||||
// is refcounted and uses a background thread.
|
||||
static scoped_refptr<SelectFileDialog> Create(
|
||||
Listener* listener,
|
||||
- std::unique_ptr<SelectFilePolicy> policy);
|
||||
+ std::unique_ptr<SelectFilePolicy> policy,
|
||||
+ bool run_from_cef = false);
|
||||
|
||||
SelectFileDialog(const SelectFileDialog&) = delete;
|
||||
SelectFileDialog& operator=(const SelectFileDialog&) = delete;
|
||||
@@ -205,6 +206,19 @@ class SHELL_DIALOGS_EXPORT SelectFileDialog
|
||||
void* params);
|
||||
bool HasMultipleFileTypeChoices();
|
||||
|
||||
+ // Match the types used by CefWindowHandle.
|
||||
+#if BUILDFLAG(IS_MAC)
|
||||
+ using WidgetType = void*;
|
||||
+ static constexpr WidgetType kNullWidget = nullptr;
|
||||
+#else
|
||||
+ using WidgetType = gfx::AcceleratedWidget;
|
||||
+ static constexpr WidgetType kNullWidget = gfx::kNullAcceleratedWidget;
|
||||
+#endif
|
||||
+
|
||||
+ void set_owning_widget(WidgetType widget) {
|
||||
+ owning_widget_ = widget;
|
||||
+ }
|
||||
+
|
||||
protected:
|
||||
friend class base::RefCountedThreadSafe<SelectFileDialog>;
|
||||
|
||||
@@ -229,6 +243,11 @@ class SHELL_DIALOGS_EXPORT SelectFileDialog
|
||||
// The listener to be notified of selection completion.
|
||||
raw_ptr<Listener> listener_;
|
||||
|
||||
+ std::unique_ptr<SelectFilePolicy> select_file_policy_;
|
||||
+
|
||||
+ // Support override of the |owning_window| value.
|
||||
+ WidgetType owning_widget_ = kNullWidget;
|
||||
+
|
||||
private:
|
||||
// Tests if the file selection dialog can be displayed by
|
||||
// testing if the AllowFileSelectionDialogs-Policy is
|
||||
@@ -241,8 +260,6 @@ class SHELL_DIALOGS_EXPORT SelectFileDialog
|
||||
|
||||
// Returns true if the dialog has multiple file type choices.
|
||||
virtual bool HasMultipleFileTypeChoicesImpl() = 0;
|
||||
-
|
||||
- std::unique_ptr<SelectFilePolicy> select_file_policy_;
|
||||
};
|
||||
|
||||
SelectFileDialog* CreateSelectFileDialog(
|
||||
diff --git ui/shell_dialogs/select_file_dialog_factory.h ui/shell_dialogs/select_file_dialog_factory.h
|
||||
index 567f50de40b04..1fbac69307bdc 100644
|
||||
--- ui/shell_dialogs/select_file_dialog_factory.h
|
||||
+++ ui/shell_dialogs/select_file_dialog_factory.h
|
||||
@@ -24,6 +24,8 @@ class SHELL_DIALOGS_EXPORT SelectFileDialogFactory {
|
||||
virtual SelectFileDialog* Create(
|
||||
ui::SelectFileDialog::Listener* listener,
|
||||
std::unique_ptr<ui::SelectFilePolicy> policy) = 0;
|
||||
+
|
||||
+ virtual bool IsCefFactory() const { return false; }
|
||||
};
|
||||
|
||||
} // namespace ui
|
||||
diff --git ui/shell_dialogs/select_file_dialog_mac.mm ui/shell_dialogs/select_file_dialog_mac.mm
|
||||
index 605c2278407ce..26ca067d32720 100644
|
||||
--- ui/shell_dialogs/select_file_dialog_mac.mm
|
||||
+++ ui/shell_dialogs/select_file_dialog_mac.mm
|
||||
@@ -100,6 +100,10 @@ void SelectFileDialogImpl::SelectFileImpl(
|
||||
mojo_window->CreateSelectFileDialog(std::move(receiver));
|
||||
} else {
|
||||
NSWindow* ns_window = gfx_window.GetNativeNSWindow();
|
||||
+ if (!ns_window && owning_widget_) {
|
||||
+ NSView* view = ((__bridge NSView*)owning_widget_);
|
||||
+ ns_window = [view window];
|
||||
+ }
|
||||
mojo::MakeSelfOwnedReceiver(
|
||||
std::make_unique<remote_cocoa::SelectFileDialogBridge>(ns_window),
|
||||
std::move(receiver));
|
||||
diff --git ui/shell_dialogs/select_file_dialog_win.cc ui/shell_dialogs/select_file_dialog_win.cc
|
||||
index e2959960598a2..477992b18730b 100644
|
||||
--- ui/shell_dialogs/select_file_dialog_win.cc
|
||||
+++ ui/shell_dialogs/select_file_dialog_win.cc
|
||||
@@ -248,6 +248,8 @@ void SelectFileDialogImpl::SelectFileImpl(
|
||||
HWND owner = owning_window && owning_window->GetRootWindow()
|
||||
? owning_window->GetHost()->GetAcceleratedWidget()
|
||||
: nullptr;
|
||||
+ if (!owner)
|
||||
+ owner = owning_widget_;
|
||||
|
||||
std::unique_ptr<RunState> run_state = BeginRun(owner);
|
||||
|
|
@ -1,145 +0,0 @@
|
|||
diff --git chrome/browser/ui/BUILD.gn chrome/browser/ui/BUILD.gn
|
||||
index 936021a313995..2dd2554f8a7c5 100644
|
||||
--- chrome/browser/ui/BUILD.gn
|
||||
+++ chrome/browser/ui/BUILD.gn
|
||||
@@ -10,6 +10,7 @@ import("//build/config/features.gni")
|
||||
import("//build/config/linux/gtk/gtk.gni")
|
||||
import("//build/config/ozone.gni")
|
||||
import("//build/config/ui.gni")
|
||||
+import("//cef/libcef/features/features.gni")
|
||||
import("//chrome/browser/buildflags.gni")
|
||||
import("//chrome/common/features.gni")
|
||||
import("//chromeos/assistant/assistant.gni")
|
||||
@@ -353,6 +354,10 @@ static_library("ui") {
|
||||
"//build/config/compiler:wexit_time_destructors",
|
||||
]
|
||||
|
||||
+ if (enable_cef) {
|
||||
+ configs += [ "//cef/libcef/features:config" ]
|
||||
+ }
|
||||
+
|
||||
# Since browser and browser_ui actually depend on each other,
|
||||
# we must omit the dependency from browser_ui to browser.
|
||||
# However, this means browser_ui and browser should more or less
|
||||
@@ -375,6 +380,7 @@ static_library("ui") {
|
||||
"//build:branding_buildflags",
|
||||
"//build:chromeos_buildflags",
|
||||
"//cc/paint",
|
||||
+ "//cef/libcef/features",
|
||||
"//chrome:extra_resources",
|
||||
"//chrome:resources",
|
||||
"//chrome:strings",
|
||||
@@ -5301,6 +5307,7 @@ static_library("ui") {
|
||||
if (enable_basic_printing) {
|
||||
deps += [
|
||||
"//components/printing/browser",
|
||||
+ "//components/printing/common:mojo_interfaces",
|
||||
"//printing",
|
||||
]
|
||||
}
|
||||
diff --git chrome/browser/ui/webui/net_export_ui.cc chrome/browser/ui/webui/net_export_ui.cc
|
||||
index 12edced619355..3a1eb1461ab08 100644
|
||||
--- chrome/browser/ui/webui/net_export_ui.cc
|
||||
+++ chrome/browser/ui/webui/net_export_ui.cc
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "base/task/single_thread_task_runner.h"
|
||||
#include "base/values.h"
|
||||
#include "build/build_config.h"
|
||||
+#include "cef/libcef/features/runtime.h"
|
||||
#include "chrome/browser/browser_process.h"
|
||||
#include "chrome/browser/download/download_prefs.h"
|
||||
#include "chrome/browser/net/net_export_helper.h"
|
||||
@@ -45,6 +46,10 @@
|
||||
#include "net/log/net_log_capture_mode.h"
|
||||
#include "ui/shell_dialogs/select_file_dialog.h"
|
||||
|
||||
+#if BUILDFLAG(ENABLE_CEF)
|
||||
+#include "cef/libcef/browser/alloy/alloy_dialog_util.h"
|
||||
+#endif
|
||||
+
|
||||
#if BUILDFLAG(IS_ANDROID)
|
||||
#include "components/browser_ui/share/android/intent_helper.h"
|
||||
#endif
|
||||
@@ -142,6 +147,13 @@ class NetExportMessageHandler
|
||||
// NetLog file.
|
||||
void ShowSelectFileDialog(const base::FilePath& default_path);
|
||||
|
||||
+#if BUILDFLAG(ENABLE_CEF)
|
||||
+ void ShowCefSaveAsDialog(content::WebContents* web_contents);
|
||||
+ void SaveAsDialogDismissed(
|
||||
+ int selected_accept_filter,
|
||||
+ const std::vector<base::FilePath>& file_paths);
|
||||
+#endif
|
||||
+
|
||||
// Cached pointer to SystemNetworkContextManager's NetExportFileWriter.
|
||||
raw_ptr<net_log::NetExportFileWriter> file_writer_;
|
||||
|
||||
@@ -235,6 +247,13 @@ void NetExportMessageHandler::OnStartNetLog(const base::ListValue* list) {
|
||||
if (UsingMobileUI()) {
|
||||
StartNetLog(base::FilePath());
|
||||
} else {
|
||||
+#if BUILDFLAG(ENABLE_CEF)
|
||||
+ if (cef::IsAlloyRuntimeEnabled()) {
|
||||
+ ShowCefSaveAsDialog(web_ui()->GetWebContents());
|
||||
+ return;
|
||||
+ }
|
||||
+#endif
|
||||
+
|
||||
base::FilePath initial_dir = last_save_dir.Pointer()->empty() ?
|
||||
DownloadPrefs::FromBrowserContext(
|
||||
web_ui()->GetWebContents()->GetBrowserContext())->DownloadPath() :
|
||||
@@ -251,6 +270,7 @@ void NetExportMessageHandler::OnStopNetLog(const base::ListValue* list) {
|
||||
std::unique_ptr<base::DictionaryValue> ui_thread_polled_data(
|
||||
new base::DictionaryValue());
|
||||
|
||||
+ if (!cef::IsAlloyRuntimeEnabled()) {
|
||||
Profile* profile = Profile::FromWebUI(web_ui());
|
||||
SetIfNotNull(ui_thread_polled_data.get(), "prerenderInfo",
|
||||
chrome_browser_net::GetPrerenderInfo(profile));
|
||||
@@ -260,6 +280,7 @@ void NetExportMessageHandler::OnStopNetLog(const base::ListValue* list) {
|
||||
SetIfNotNull(ui_thread_polled_data.get(), "serviceProviders",
|
||||
chrome_browser_net::GetWindowsServiceProviders());
|
||||
#endif
|
||||
+ }
|
||||
|
||||
file_writer_->StopNetLog(std::move(ui_thread_polled_data));
|
||||
}
|
||||
@@ -375,6 +396,38 @@ void NetExportMessageHandler::ShowSelectFileDialog(
|
||||
&file_type_info, 0, base::FilePath::StringType(), owning_window, nullptr);
|
||||
}
|
||||
|
||||
+#if BUILDFLAG(ENABLE_CEF)
|
||||
+
|
||||
+void NetExportMessageHandler::ShowCefSaveAsDialog(
|
||||
+ content::WebContents* web_contents) {
|
||||
+ base::FilePath initial_dir;
|
||||
+ if (!last_save_dir.Pointer()->empty())
|
||||
+ initial_dir = *last_save_dir.Pointer();
|
||||
+ base::FilePath initial_path =
|
||||
+ initial_dir.Append(FILE_PATH_LITERAL("chrome-net-export-log.json"));
|
||||
+
|
||||
+ blink::mojom::FileChooserParams params;
|
||||
+ params.mode = blink::mojom::FileChooserParams::Mode::kSave;
|
||||
+ params.default_file_name = initial_path;
|
||||
+ params.accept_types.push_back(
|
||||
+ alloy::FilePathTypeToString16(initial_path.Extension()));
|
||||
+
|
||||
+ alloy::RunFileChooser(web_contents, params,
|
||||
+ base::BindOnce(&NetExportMessageHandler::SaveAsDialogDismissed,
|
||||
+ weak_ptr_factory_.GetWeakPtr()));
|
||||
+}
|
||||
+
|
||||
+void NetExportMessageHandler::SaveAsDialogDismissed(
|
||||
+ int selected_accept_filter,
|
||||
+ const std::vector<base::FilePath>& file_paths) {
|
||||
+ if (file_paths.size() == 1) {
|
||||
+ *last_save_dir.Pointer() = file_paths[0].DirName();
|
||||
+ StartNetLog(file_paths[0]);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+#endif // BUILDFLAG(ENABLE_CEF)
|
||||
+
|
||||
} // namespace
|
||||
|
||||
NetExportUI::NetExportUI(content::WebUI* web_ui) : WebUIController(web_ui) {
|
|
@ -135,159 +135,6 @@ index f6098966f5b34..da78289b66155 100644
|
|||
#endif
|
||||
}
|
||||
|
||||
diff --git chrome/browser/ui/webui/print_preview/pdf_printer_handler.cc chrome/browser/ui/webui/print_preview/pdf_printer_handler.cc
|
||||
index 86e16795ce43d..9053975ad42f6 100644
|
||||
--- chrome/browser/ui/webui/print_preview/pdf_printer_handler.cc
|
||||
+++ chrome/browser/ui/webui/print_preview/pdf_printer_handler.cc
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "base/values.h"
|
||||
#include "build/build_config.h"
|
||||
#include "build/chromeos_buildflags.h"
|
||||
+#include "cef/libcef/features/runtime.h"
|
||||
#include "chrome/browser/app_mode/app_mode_utils.h"
|
||||
#include "chrome/browser/browser_process.h"
|
||||
#include "chrome/browser/download/download_prefs.h"
|
||||
@@ -62,6 +63,10 @@
|
||||
#include "chromeos/lacros/lacros_service.h"
|
||||
#endif
|
||||
|
||||
+#if BUILDFLAG(ENABLE_CEF)
|
||||
+#include "cef/libcef/browser/alloy/alloy_dialog_util.h"
|
||||
+#endif
|
||||
+
|
||||
namespace printing {
|
||||
|
||||
namespace {
|
||||
@@ -414,16 +419,18 @@ void PdfPrinterHandler::SelectFile(const base::FilePath& default_filename,
|
||||
service->GetRemote<crosapi::mojom::DriveIntegrationService>()
|
||||
->GetMountPointPath(
|
||||
base::BindOnce(&PdfPrinterHandler::OnSaveLocationReady,
|
||||
- weak_ptr_factory_.GetWeakPtr(),
|
||||
+ weak_ptr_factory_.GetWeakPtr(), initiator,
|
||||
std::move(default_filename), prompt_user));
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
- OnSaveLocationReady(default_filename, prompt_user, GetSaveLocation());
|
||||
+ OnSaveLocationReady(initiator, default_filename, prompt_user,
|
||||
+ GetSaveLocation());
|
||||
}
|
||||
|
||||
void PdfPrinterHandler::OnSaveLocationReady(
|
||||
+ content::WebContents* initiator,
|
||||
const base::FilePath& default_filename,
|
||||
bool prompt_user,
|
||||
const base::FilePath& path) {
|
||||
@@ -441,10 +448,27 @@ void PdfPrinterHandler::OnSaveLocationReady(
|
||||
// If the directory is empty there is no reason to create it or use the
|
||||
// default location.
|
||||
if (path.empty()) {
|
||||
+#if BUILDFLAG(ENABLE_CEF)
|
||||
+ if (cef::IsAlloyRuntimeEnabled()) {
|
||||
+ ShowCefSaveAsDialog(initiator, default_filename, path);
|
||||
+ return;
|
||||
+ }
|
||||
+#endif
|
||||
OnDirectorySelected(default_filename, path);
|
||||
return;
|
||||
}
|
||||
|
||||
+ auto callback = base::BindOnce(&PdfPrinterHandler::OnDirectorySelected,
|
||||
+ weak_ptr_factory_.GetWeakPtr(),
|
||||
+ default_filename);
|
||||
+#if BUILDFLAG(ENABLE_CEF)
|
||||
+ if (cef::IsAlloyRuntimeEnabled()) {
|
||||
+ callback = base::BindOnce(&PdfPrinterHandler::ShowCefSaveAsDialog,
|
||||
+ weak_ptr_factory_.GetWeakPtr(), initiator,
|
||||
+ default_filename);
|
||||
+ }
|
||||
+#endif
|
||||
+
|
||||
// Get default download directory. This will be used as a fallback if the
|
||||
// save directory does not exist.
|
||||
DownloadPrefs* download_prefs = DownloadPrefs::FromBrowserContext(profile_);
|
||||
@@ -452,8 +476,7 @@ void PdfPrinterHandler::OnSaveLocationReady(
|
||||
base::ThreadPool::PostTaskAndReplyWithResult(
|
||||
FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT},
|
||||
base::BindOnce(&SelectSaveDirectory, path, default_path),
|
||||
- base::BindOnce(&PdfPrinterHandler::OnDirectorySelected,
|
||||
- weak_ptr_factory_.GetWeakPtr(), default_filename));
|
||||
+ std::move(callback));
|
||||
}
|
||||
|
||||
void PdfPrinterHandler::PostPrintToPdfTask() {
|
||||
@@ -499,6 +522,36 @@ void PdfPrinterHandler::OnDirectorySelected(const base::FilePath& filename,
|
||||
platform_util::GetTopLevel(preview_web_contents_->GetNativeView()), NULL);
|
||||
}
|
||||
|
||||
+#if BUILDFLAG(ENABLE_CEF)
|
||||
+
|
||||
+void PdfPrinterHandler::ShowCefSaveAsDialog(content::WebContents* initiator,
|
||||
+ const base::FilePath& filename,
|
||||
+ const base::FilePath& directory) {
|
||||
+ base::FilePath path = directory.Append(filename);
|
||||
+
|
||||
+ blink::mojom::FileChooserParams params;
|
||||
+ params.mode = blink::mojom::FileChooserParams::Mode::kSave;
|
||||
+ params.default_file_name = path;
|
||||
+ params.accept_types.push_back(
|
||||
+ alloy::FilePathTypeToString16(path.Extension()));
|
||||
+
|
||||
+ alloy::RunFileChooser(initiator, params,
|
||||
+ base::BindOnce(&PdfPrinterHandler::SaveAsDialogDismissed,
|
||||
+ weak_ptr_factory_.GetWeakPtr()));
|
||||
+}
|
||||
+
|
||||
+void PdfPrinterHandler::SaveAsDialogDismissed(
|
||||
+ int selected_accept_filter,
|
||||
+ const std::vector<base::FilePath>& file_paths) {
|
||||
+ if (file_paths.size() == 1) {
|
||||
+ FileSelected(file_paths[0], 0, nullptr);
|
||||
+ } else {
|
||||
+ FileSelectionCanceled(nullptr);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+#endif // BUILDFLAG(ENABLE_CEF)
|
||||
+
|
||||
base::FilePath PdfPrinterHandler::GetSaveLocation() const {
|
||||
#if BUILDFLAG(IS_CHROMEOS_ASH)
|
||||
drive::DriveIntegrationService* drive_service =
|
||||
diff --git chrome/browser/ui/webui/print_preview/pdf_printer_handler.h chrome/browser/ui/webui/print_preview/pdf_printer_handler.h
|
||||
index 46c8b1d08b075..1ee95cd7c3240 100644
|
||||
--- chrome/browser/ui/webui/print_preview/pdf_printer_handler.h
|
||||
+++ chrome/browser/ui/webui/print_preview/pdf_printer_handler.h
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "base/memory/ref_counted.h"
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "build/chromeos_buildflags.h"
|
||||
+#include "cef/libcef/features/features.h"
|
||||
#include "chrome/browser/ui/webui/print_preview/printer_handler.h"
|
||||
#include "ui/shell_dialogs/select_file_dialog.h"
|
||||
|
||||
@@ -95,10 +96,20 @@ class PdfPrinterHandler : public PrinterHandler,
|
||||
void OnDirectorySelected(const base::FilePath& filename,
|
||||
const base::FilePath& directory);
|
||||
|
||||
- void OnSaveLocationReady(const base::FilePath& default_filename,
|
||||
+ void OnSaveLocationReady(content::WebContents* initiator,
|
||||
+ const base::FilePath& default_filename,
|
||||
bool prompt_user,
|
||||
const base::FilePath& path);
|
||||
|
||||
+#if BUILDFLAG(ENABLE_CEF)
|
||||
+ void ShowCefSaveAsDialog(content::WebContents* initiator,
|
||||
+ const base::FilePath& filename,
|
||||
+ const base::FilePath& directory);
|
||||
+
|
||||
+ void SaveAsDialogDismissed(int selected_accept_filter,
|
||||
+ const std::vector<base::FilePath>& file_paths);
|
||||
+#endif
|
||||
+
|
||||
// Return save location as the Drive mount or fetch from Download Preferences.
|
||||
base::FilePath GetSaveLocation() const;
|
||||
|
||||
diff --git chrome/browser/ui/webui/print_preview/print_preview_ui.cc chrome/browser/ui/webui/print_preview/print_preview_ui.cc
|
||||
index eba14d78d87ff..7901f000a44b5 100644
|
||||
--- chrome/browser/ui/webui/print_preview/print_preview_ui.cc
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -136,6 +136,7 @@ GtkWindow* GetWindow(CefRefPtr<CefBrowser> browser) {
|
|||
RootWindow::GetForBrowser(browser->GetIdentifier());
|
||||
if (root_window) {
|
||||
GtkWidget* window = root_window->GetWindowHandle();
|
||||
DCHECK(window);
|
||||
if (!window)
|
||||
LOG(ERROR) << "No GtkWindow for browser";
|
||||
return GTK_WINDOW(window);
|
||||
|
@ -153,7 +154,6 @@ bool ClientDialogHandlerGtk::OnFileDialog(
|
|||
const CefString& title,
|
||||
const CefString& default_file_path,
|
||||
const std::vector<CefString>& accept_filters,
|
||||
int selected_accept_filter,
|
||||
CefRefPtr<CefFileDialogCallback> callback) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
|
||||
|
@ -163,7 +163,6 @@ bool ClientDialogHandlerGtk::OnFileDialog(
|
|||
params.title = title;
|
||||
params.default_file_path = default_file_path;
|
||||
params.accept_filters = accept_filters;
|
||||
params.selected_accept_filter = selected_accept_filter;
|
||||
params.callback = callback;
|
||||
|
||||
GetWindowAndContinue(
|
||||
|
@ -221,7 +220,8 @@ void ClientDialogHandlerGtk::OnResetDialogState(CefRefPtr<CefBrowser> browser) {
|
|||
js_dialog_callback_ = nullptr;
|
||||
}
|
||||
|
||||
void ClientDialogHandlerGtk::OnFileDialogContinue(OnFileDialogParams params,
|
||||
void ClientDialogHandlerGtk::OnFileDialogContinue(
|
||||
const OnFileDialogParams& params,
|
||||
GtkWindow* window) {
|
||||
REQUIRE_MAIN_THREAD();
|
||||
|
||||
|
@ -232,17 +232,14 @@ void ClientDialogHandlerGtk::OnFileDialogContinue(OnFileDialogParams params,
|
|||
GtkFileChooserAction action;
|
||||
const gchar* accept_button;
|
||||
|
||||
// Remove any modifier flags.
|
||||
FileDialogMode mode_type =
|
||||
static_cast<FileDialogMode>(params.mode & FILE_DIALOG_TYPE_MASK);
|
||||
|
||||
if (mode_type == FILE_DIALOG_OPEN || mode_type == FILE_DIALOG_OPEN_MULTIPLE) {
|
||||
if (params.mode == FILE_DIALOG_OPEN ||
|
||||
params.mode == FILE_DIALOG_OPEN_MULTIPLE) {
|
||||
action = GTK_FILE_CHOOSER_ACTION_OPEN;
|
||||
accept_button = "_Open";
|
||||
} else if (mode_type == FILE_DIALOG_OPEN_FOLDER) {
|
||||
} else if (params.mode == FILE_DIALOG_OPEN_FOLDER) {
|
||||
action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
|
||||
accept_button = "_Open";
|
||||
} else if (mode_type == FILE_DIALOG_SAVE) {
|
||||
} else if (params.mode == FILE_DIALOG_SAVE) {
|
||||
action = GTK_FILE_CHOOSER_ACTION_SAVE;
|
||||
accept_button = "_Save";
|
||||
} else {
|
||||
|
@ -255,7 +252,7 @@ void ClientDialogHandlerGtk::OnFileDialogContinue(OnFileDialogParams params,
|
|||
if (!params.title.empty()) {
|
||||
title_str = params.title;
|
||||
} else {
|
||||
switch (mode_type) {
|
||||
switch (params.mode) {
|
||||
case FILE_DIALOG_OPEN:
|
||||
title_str = "Open File";
|
||||
break;
|
||||
|
@ -277,19 +274,10 @@ void ClientDialogHandlerGtk::OnFileDialogContinue(OnFileDialogParams params,
|
|||
title_str.c_str(), GTK_WINDOW(window), action, "_Cancel",
|
||||
GTK_RESPONSE_CANCEL, accept_button, GTK_RESPONSE_ACCEPT, nullptr);
|
||||
|
||||
if (mode_type == FILE_DIALOG_OPEN_MULTIPLE)
|
||||
if (params.mode == FILE_DIALOG_OPEN_MULTIPLE)
|
||||
gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), TRUE);
|
||||
|
||||
if (mode_type == FILE_DIALOG_SAVE) {
|
||||
gtk_file_chooser_set_do_overwrite_confirmation(
|
||||
GTK_FILE_CHOOSER(dialog),
|
||||
!!(params.mode & FILE_DIALOG_OVERWRITEPROMPT_FLAG));
|
||||
}
|
||||
|
||||
gtk_file_chooser_set_show_hidden(
|
||||
GTK_FILE_CHOOSER(dialog), !(params.mode & FILE_DIALOG_HIDEREADONLY_FLAG));
|
||||
|
||||
if (!params.default_file_path.empty() && mode_type == FILE_DIALOG_SAVE) {
|
||||
if (!params.default_file_path.empty() && params.mode == FILE_DIALOG_SAVE) {
|
||||
const std::string& file_path = params.default_file_path;
|
||||
bool exists = false;
|
||||
|
||||
|
@ -310,20 +298,17 @@ void ClientDialogHandlerGtk::OnFileDialogContinue(OnFileDialogParams params,
|
|||
|
||||
std::vector<GtkFileFilter*> filters;
|
||||
AddFilters(GTK_FILE_CHOOSER(dialog), params.accept_filters, true, &filters);
|
||||
if (params.selected_accept_filter < static_cast<int>(filters.size())) {
|
||||
gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog),
|
||||
filters[params.selected_accept_filter]);
|
||||
}
|
||||
|
||||
bool success = false;
|
||||
|
||||
if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
|
||||
if (mode_type == FILE_DIALOG_OPEN || mode_type == FILE_DIALOG_OPEN_FOLDER ||
|
||||
mode_type == FILE_DIALOG_SAVE) {
|
||||
if (params.mode == FILE_DIALOG_OPEN ||
|
||||
params.mode == FILE_DIALOG_OPEN_FOLDER ||
|
||||
params.mode == FILE_DIALOG_SAVE) {
|
||||
char* filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
|
||||
files.push_back(std::string(filename));
|
||||
success = true;
|
||||
} else if (mode_type == FILE_DIALOG_OPEN_MULTIPLE) {
|
||||
} else if (params.mode == FILE_DIALOG_OPEN_MULTIPLE) {
|
||||
GSList* filenames =
|
||||
gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog));
|
||||
if (filenames) {
|
||||
|
@ -339,29 +324,15 @@ void ClientDialogHandlerGtk::OnFileDialogContinue(OnFileDialogParams params,
|
|||
}
|
||||
}
|
||||
|
||||
int filter_index = params.selected_accept_filter;
|
||||
if (success) {
|
||||
GtkFileFilter* selected_filter =
|
||||
gtk_file_chooser_get_filter(GTK_FILE_CHOOSER(dialog));
|
||||
if (selected_filter != nullptr) {
|
||||
for (size_t x = 0; x < filters.size(); ++x) {
|
||||
if (filters[x] == selected_filter) {
|
||||
filter_index = x;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gtk_widget_destroy(dialog);
|
||||
|
||||
if (success)
|
||||
params.callback->Continue(filter_index, files);
|
||||
params.callback->Continue(files);
|
||||
else
|
||||
params.callback->Cancel();
|
||||
}
|
||||
|
||||
void ClientDialogHandlerGtk::OnJSDialogContinue(OnJSDialogParams params,
|
||||
void ClientDialogHandlerGtk::OnJSDialogContinue(const OnJSDialogParams& params,
|
||||
GtkWindow* window) {
|
||||
REQUIRE_MAIN_THREAD();
|
||||
|
||||
|
|
|
@ -25,7 +25,6 @@ class ClientDialogHandlerGtk : public CefDialogHandler,
|
|||
const CefString& title,
|
||||
const CefString& default_file_path,
|
||||
const std::vector<CefString>& accept_filters,
|
||||
int selected_accept_filter,
|
||||
CefRefPtr<CefFileDialogCallback> callback) override;
|
||||
|
||||
// CefJSDialogHandler methods.
|
||||
|
@ -49,10 +48,10 @@ class ClientDialogHandlerGtk : public CefDialogHandler,
|
|||
CefString title;
|
||||
CefString default_file_path;
|
||||
std::vector<CefString> accept_filters;
|
||||
int selected_accept_filter;
|
||||
CefRefPtr<CefFileDialogCallback> callback;
|
||||
};
|
||||
void OnFileDialogContinue(OnFileDialogParams params, GtkWindow* window);
|
||||
void OnFileDialogContinue(const OnFileDialogParams& params,
|
||||
GtkWindow* window);
|
||||
|
||||
struct OnJSDialogParams {
|
||||
CefRefPtr<CefBrowser> browser;
|
||||
|
@ -62,7 +61,7 @@ class ClientDialogHandlerGtk : public CefDialogHandler,
|
|||
CefString default_prompt_text;
|
||||
CefRefPtr<CefJSDialogCallback> callback;
|
||||
};
|
||||
void OnJSDialogContinue(OnJSDialogParams params, GtkWindow* window);
|
||||
void OnJSDialogContinue(const OnJSDialogParams& params, GtkWindow* window);
|
||||
|
||||
void GetWindowAndContinue(CefRefPtr<CefBrowser> browser,
|
||||
base::OnceCallback<void(GtkWindow*)> callback);
|
||||
|
|
|
@ -17,7 +17,8 @@ namespace dialog_test {
|
|||
namespace {
|
||||
|
||||
const char kTestUrlPath[] = "/dialogs";
|
||||
const char kFileOpenMessageName[] = "DialogTest.FileOpen";
|
||||
const char kFileOpenPngMessageName[] = "DialogTest.FileOpenPng";
|
||||
const char kFileOpenImageMessageName[] = "DialogTest.FileOpenImage";
|
||||
const char kFileOpenMultipleMessageName[] = "DialogTest.FileOpenMultiple";
|
||||
const char kFileOpenFolderMessageName[] = "DialogTest.FileOpenFolder";
|
||||
const char kFileSaveMessageName[] = "DialogTest.FileSave";
|
||||
|
@ -25,11 +26,9 @@ const char kFileSaveMessageName[] = "DialogTest.FileSave";
|
|||
// Store persistent dialog state information.
|
||||
class DialogState : public base::RefCountedThreadSafe<DialogState> {
|
||||
public:
|
||||
DialogState()
|
||||
: mode_(FILE_DIALOG_OPEN), last_selected_filter_(0), pending_(false) {}
|
||||
DialogState() : mode_(FILE_DIALOG_OPEN), pending_(false) {}
|
||||
|
||||
cef_file_dialog_mode_t mode_;
|
||||
int last_selected_filter_;
|
||||
CefString last_file_;
|
||||
bool pending_;
|
||||
|
||||
|
@ -45,15 +44,11 @@ class DialogCallback : public CefRunFileDialogCallback {
|
|||
: router_callback_(router_callback), dialog_state_(dialog_state) {}
|
||||
|
||||
virtual void OnFileDialogDismissed(
|
||||
int last_selected_filter,
|
||||
const std::vector<CefString>& file_paths) override {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
DCHECK(dialog_state_->pending_);
|
||||
|
||||
if (!file_paths.empty()) {
|
||||
if (dialog_state_->mode_ != FILE_DIALOG_OPEN_FOLDER)
|
||||
dialog_state_->last_selected_filter_ = last_selected_filter;
|
||||
|
||||
dialog_state_->last_file_ = file_paths[0];
|
||||
if (dialog_state_->mode_ == FILE_DIALOG_OPEN_FOLDER) {
|
||||
std::string last_file = dialog_state_->last_file_;
|
||||
|
@ -118,25 +113,30 @@ class Handler : public CefMessageRouterBrowserSide::Handler {
|
|||
std::string title;
|
||||
|
||||
const std::string& message_name = request;
|
||||
if (message_name == kFileOpenMessageName) {
|
||||
if (message_name == kFileOpenPngMessageName) {
|
||||
dialog_state_->mode_ = FILE_DIALOG_OPEN;
|
||||
title = "My Open Dialog";
|
||||
title = "My Open PNG Dialog";
|
||||
accept_filters.push_back(".png");
|
||||
} else if (message_name == kFileOpenImageMessageName) {
|
||||
dialog_state_->mode_ = FILE_DIALOG_OPEN;
|
||||
title = "My Open Image Dialog";
|
||||
accept_filters.push_back("image/*");
|
||||
} else if (message_name == kFileOpenMultipleMessageName) {
|
||||
dialog_state_->mode_ = FILE_DIALOG_OPEN_MULTIPLE;
|
||||
title = "My Open Multiple Dialog";
|
||||
title = "My Open MultiType Dialog";
|
||||
} else if (message_name == kFileOpenFolderMessageName) {
|
||||
dialog_state_->mode_ = FILE_DIALOG_OPEN_FOLDER;
|
||||
title = "My Open Folder Dialog";
|
||||
} else if (message_name == kFileSaveMessageName) {
|
||||
dialog_state_->mode_ = static_cast<cef_file_dialog_mode_t>(
|
||||
FILE_DIALOG_SAVE | FILE_DIALOG_OVERWRITEPROMPT_FLAG);
|
||||
dialog_state_->mode_ = FILE_DIALOG_SAVE;
|
||||
title = "My Save Dialog";
|
||||
} else {
|
||||
NOTREACHED();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (dialog_state_->mode_ != FILE_DIALOG_OPEN_FOLDER) {
|
||||
if (accept_filters.empty() &&
|
||||
dialog_state_->mode_ != FILE_DIALOG_OPEN_FOLDER) {
|
||||
// Build filters based on mime time.
|
||||
accept_filters.push_back("text/*");
|
||||
|
||||
|
@ -154,7 +154,6 @@ class Handler : public CefMessageRouterBrowserSide::Handler {
|
|||
|
||||
browser->GetHost()->RunFileDialog(
|
||||
dialog_state_->mode_, title, dialog_state_->last_file_, accept_filters,
|
||||
dialog_state_->last_selected_filter_,
|
||||
new DialogCallback(callback, dialog_state_));
|
||||
|
||||
return true;
|
||||
|
|
|
@ -312,17 +312,12 @@ void EndTracing(CefRefPtr<CefBrowser> browser) {
|
|||
|
||||
// Results in a call to OnFileDialogDismissed.
|
||||
browser_->GetHost()->RunFileDialog(
|
||||
static_cast<cef_file_dialog_mode_t>(FILE_DIALOG_SAVE |
|
||||
FILE_DIALOG_OVERWRITEPROMPT_FLAG),
|
||||
CefString(), // title
|
||||
path,
|
||||
std::vector<CefString>(), // accept_filters
|
||||
0, // selected_accept_filter
|
||||
this);
|
||||
FILE_DIALOG_SAVE,
|
||||
/*title=*/CefString(), path,
|
||||
/*accept_filters=*/std::vector<CefString>(), this);
|
||||
}
|
||||
|
||||
void OnFileDialogDismissed(
|
||||
int selected_accept_filter,
|
||||
const std::vector<CefString>& file_paths) override {
|
||||
if (!file_paths.empty()) {
|
||||
// File selected. Results in a call to OnEndTracingComplete.
|
||||
|
@ -370,17 +365,12 @@ void PrintToPDF(CefRefPtr<CefBrowser> browser) {
|
|||
accept_filters.push_back(".pdf");
|
||||
|
||||
// Results in a call to OnFileDialogDismissed.
|
||||
browser_->GetHost()->RunFileDialog(
|
||||
static_cast<cef_file_dialog_mode_t>(FILE_DIALOG_SAVE |
|
||||
FILE_DIALOG_OVERWRITEPROMPT_FLAG),
|
||||
CefString(), // title
|
||||
path, accept_filters,
|
||||
0, // selected_accept_filter
|
||||
this);
|
||||
browser_->GetHost()->RunFileDialog(FILE_DIALOG_SAVE,
|
||||
/*title=*/CefString(), path,
|
||||
accept_filters, this);
|
||||
}
|
||||
|
||||
void OnFileDialogDismissed(
|
||||
int selected_accept_filter,
|
||||
const std::vector<CefString>& file_paths) override {
|
||||
if (!file_paths.empty()) {
|
||||
CefPdfPrintSettings settings;
|
||||
|
|
|
@ -65,10 +65,13 @@ Click a button to show the associated dialog type.
|
|||
<br/><input type="button" onclick="show_alert();" value="Show Alert">
|
||||
<br/><input type="button" onclick="show_confirm();" value="Show Confirm"> <span id="cm"></span>
|
||||
<br/><input type="button" onclick="show_prompt();" value="Show Prompt"> <span id="pm"></span>
|
||||
<br/>input type="file": <input type="file" name="pic" accept="text/*,.js,.css,image/*">
|
||||
<br/>input type="file" (.png): <input type="file" name="pic" accept=".png">
|
||||
<br/>input type="file" (image/*): <input type="file" name="pic" accept="image/*">
|
||||
<br/>input type="file" (multiple types): <input type="file" name="pic" accept="text/*,.js,.css,image/*">
|
||||
<br/>input type="file" (directory): <input type="file" webkitdirectory accept="text/*,.js,.css,image/*">
|
||||
<br/><input type="button" onclick="show_file_dialog('fo', 'FileOpen');" value="Show File Open" disabled="true"> <span id="fo"></span>
|
||||
<br/><input type="button" onclick="show_file_dialog('fom', 'FileOpenMultiple');" value="Show File Open Multiple" disabled="true"> <span id="fom"></span>
|
||||
<br/><input type="button" onclick="show_file_dialog('fop', 'FileOpenPng');" value="Show File Open (.png)" disabled="true"> <span id="fop"></span>
|
||||
<br/><input type="button" onclick="show_file_dialog('foi', 'FileOpenImage');" value="Show File Open (image/*)" disabled="true"> <span id="foi"></span>
|
||||
<br/><input type="button" onclick="show_file_dialog('fom', 'FileOpenMultiple');" value="Show File Open (multiple types/files)" disabled="true"> <span id="fom"></span>
|
||||
<br/><input type="button" onclick="show_file_dialog('fof', 'FileOpenFolder');" value="Show File Open Folder" disabled="true"> <span id="fof"></span>
|
||||
<br/><input type="button" onclick="show_file_dialog('fs', 'FileSave');" value="Show File Save" disabled="true"> <span id="fs"></span>
|
||||
<p id="time"></p>
|
||||
|
|
|
@ -19,7 +19,6 @@ class DialogTestHandler : public TestHandler {
|
|||
: mode(dialog_mode),
|
||||
title("Test Title"),
|
||||
default_file_name("Test File Name"),
|
||||
selected_accept_filter(1), // Something other than 0 for testing.
|
||||
callback_async(false),
|
||||
callback_cancel(false) {
|
||||
accept_types.push_back("text/*");
|
||||
|
@ -31,7 +30,6 @@ class DialogTestHandler : public TestHandler {
|
|||
CefString title;
|
||||
CefString default_file_name;
|
||||
std::vector<CefString> accept_types;
|
||||
int selected_accept_filter;
|
||||
|
||||
bool callback_async; // True if the callback should execute asynchronously.
|
||||
bool callback_cancel; // True if the callback should cancel.
|
||||
|
@ -43,16 +41,12 @@ class DialogTestHandler : public TestHandler {
|
|||
explicit Callback(DialogTestHandler* handler) : handler_(handler) {}
|
||||
|
||||
void OnFileDialogDismissed(
|
||||
int selected_accept_filter,
|
||||
const std::vector<CefString>& file_paths) override {
|
||||
handler_->got_onfiledialogdismissed_.yes();
|
||||
|
||||
if (handler_->config_.callback_cancel) {
|
||||
EXPECT_EQ(0, selected_accept_filter);
|
||||
EXPECT_TRUE(file_paths.empty());
|
||||
} else {
|
||||
EXPECT_EQ(handler_->config_.selected_accept_filter,
|
||||
selected_accept_filter);
|
||||
TestStringVectorEqual(handler_->config_.callback_paths, file_paths);
|
||||
}
|
||||
|
||||
|
@ -81,18 +75,16 @@ class DialogTestHandler : public TestHandler {
|
|||
void OnLoadEnd(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
int httpStatusCode) override {
|
||||
browser->GetHost()->RunFileDialog(
|
||||
config_.mode, config_.title, config_.default_file_name,
|
||||
config_.accept_types, config_.selected_accept_filter,
|
||||
new Callback(this));
|
||||
browser->GetHost()->RunFileDialog(config_.mode, config_.title,
|
||||
config_.default_file_name,
|
||||
config_.accept_types, new Callback(this));
|
||||
}
|
||||
|
||||
void ExecuteCallback(CefRefPtr<CefFileDialogCallback> callback) {
|
||||
if (config_.callback_cancel)
|
||||
callback->Cancel();
|
||||
else
|
||||
callback->Continue(config_.selected_accept_filter,
|
||||
config_.callback_paths);
|
||||
callback->Continue(config_.callback_paths);
|
||||
}
|
||||
|
||||
// CefDialogHandler
|
||||
|
@ -101,7 +93,6 @@ class DialogTestHandler : public TestHandler {
|
|||
const CefString& title,
|
||||
const CefString& default_file_name,
|
||||
const std::vector<CefString>& accept_types,
|
||||
int selected_accept_filter,
|
||||
CefRefPtr<CefFileDialogCallback> callback) override {
|
||||
got_onfiledialog_.yes();
|
||||
|
||||
|
@ -155,21 +146,6 @@ TEST(DialogTest, FileEmptyParams) {
|
|||
ReleaseAndWaitForDestructor(handler);
|
||||
}
|
||||
|
||||
TEST(DialogTest, FileAdditionalFlags) {
|
||||
DialogTestHandler::TestConfig config(static_cast<cef_file_dialog_mode_t>(
|
||||
FILE_DIALOG_OPEN | FILE_DIALOG_HIDEREADONLY_FLAG |
|
||||
FILE_DIALOG_OVERWRITEPROMPT_FLAG));
|
||||
config.title.clear();
|
||||
config.default_file_name.clear();
|
||||
config.accept_types.clear();
|
||||
config.callback_async = false;
|
||||
config.callback_cancel = false;
|
||||
|
||||
CefRefPtr<DialogTestHandler> handler = new DialogTestHandler(config);
|
||||
handler->ExecuteTest();
|
||||
ReleaseAndWaitForDestructor(handler);
|
||||
}
|
||||
|
||||
TEST(DialogTest, FileOpen) {
|
||||
DialogTestHandler::TestConfig config(FILE_DIALOG_OPEN);
|
||||
config.callback_async = false;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue