Merge pull request #24620 from brave/sko/file-chooser
Show site origin in file select dialog
This commit is contained in:
@@ -1299,6 +1299,32 @@ Or change later at <ph name="SETTINGS_EXTENIONS_LINK">$2<ex>brave://settings/ext
|
||||
Brave Player
|
||||
</message>
|
||||
</if> <!-- enable_brave_player -->
|
||||
|
||||
<!-- File select -->
|
||||
<message name="IDS_BRAVE_FILE_SELECT_OPEN_TITLE" desc="">
|
||||
<ph name="SITE">$1<ex>http://foo.com</ex></ph> wants to open
|
||||
</message>
|
||||
<message name="IDS_BRAVE_FILE_SELECT_OPEN_TITLE_IFRAME" desc="">
|
||||
An embedded page on <ph name="SITE">$1<ex>http://foo.com</ex></ph> wants to open
|
||||
</message>
|
||||
<message name="IDS_BRAVE_FILE_SELECT_OPEN_TITLE_NONSTANDARD_URL" desc="">
|
||||
This page wants to open
|
||||
</message>
|
||||
<message name="IDS_BRAVE_FILE_SELECT_OPEN_TITLE_NONSTANDARD_URL_IFRAME" desc="">
|
||||
An embedded page on this page wants to open
|
||||
</message>
|
||||
<message name="IDS_BRAVE_FILE_SELECT_SAVE_TITLE" desc="">
|
||||
<ph name="SITE">$1<ex>http://foo.com</ex></ph> wants to save
|
||||
</message>
|
||||
<message name="IDS_BRAVE_FILE_SELECT_SAVE_TITLE_IFRAME" desc="">
|
||||
An embedded page on <ph name="SITE">$1<ex>http://foo.com</ex></ph> wants to save
|
||||
</message>
|
||||
<message name="IDS_BRAVE_FILE_SELECT_SAVE_TITLE_NONSTANDARD_URL" desc="">
|
||||
This page wants to save
|
||||
</message>
|
||||
<message name="IDS_BRAVE_FILE_SELECT_SAVE_TITLE_NONSTANDARD_URL_IFRAME" desc="">
|
||||
An embedded page on this page wants to save
|
||||
</message>
|
||||
<!--Add new items to the appropriate sections above -->
|
||||
</messages>
|
||||
</release>
|
||||
|
||||
+8
-1
@@ -150,6 +150,8 @@ source_set("ui") {
|
||||
"brave_browser_content_setting_bubble_model_delegate.h",
|
||||
"brave_browser_window.cc",
|
||||
"brave_browser_window.h",
|
||||
"brave_file_select_utils.cc",
|
||||
"brave_file_select_utils.h",
|
||||
"brave_icon_with_badge_image_source.cc",
|
||||
"brave_icon_with_badge_image_source.h",
|
||||
"brave_layout_constants.cc",
|
||||
@@ -1335,9 +1337,14 @@ source_set("ui") {
|
||||
source_set("unit_tests") {
|
||||
if (!is_android) {
|
||||
testonly = true
|
||||
sources = [ "brave_layout_constants_unittest.cc" ]
|
||||
sources = [
|
||||
"brave_file_select_utils_unittest.cc",
|
||||
"brave_layout_constants_unittest.cc",
|
||||
]
|
||||
deps = [
|
||||
"//brave/components/l10n/common:test_support",
|
||||
"//chrome/browser/ui",
|
||||
"//components/javascript_dialogs",
|
||||
"//testing/gtest",
|
||||
"//ui/base:test_support",
|
||||
"//ui/gfx",
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "base/functional/callback_helpers.h"
|
||||
#include "brave/browser/brave_browser_features.h"
|
||||
#include "brave/browser/ui/brave_browser_window.h"
|
||||
#include "brave/browser/ui/brave_file_select_utils.h"
|
||||
#include "brave/browser/ui/tabs/brave_tab_prefs.h"
|
||||
#include "brave/browser/ui/tabs/features.h"
|
||||
#include "brave/components/constants/pref_names.h"
|
||||
@@ -27,7 +28,9 @@
|
||||
#include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
|
||||
#include "chrome/common/webui_url_constants.h"
|
||||
#include "components/prefs/pref_service.h"
|
||||
#include "content/public/browser/file_select_listener.h"
|
||||
#include "content/public/common/url_constants.h"
|
||||
#include "third_party/blink/public/mojom/choosers/file_chooser.mojom.h"
|
||||
#include "url/gurl.h"
|
||||
|
||||
#if defined(TOOLKIT_VIEWS)
|
||||
@@ -128,6 +131,33 @@ void BraveBrowser::TabStripEmpty() {
|
||||
true, std::nullopt));
|
||||
}
|
||||
|
||||
void BraveBrowser::RunFileChooser(
|
||||
content::RenderFrameHost* render_frame_host,
|
||||
scoped_refptr<content::FileSelectListener> listener,
|
||||
const blink::mojom::FileChooserParams& params) {
|
||||
#if BUILDFLAG(IS_ANDROID)
|
||||
Browser::RunFileChooser(render_frame_host, listener, params);
|
||||
#else
|
||||
auto new_params = params.Clone();
|
||||
if (new_params->title.empty()) {
|
||||
// Fill title of file chooser with origin of the frame.
|
||||
|
||||
// Note that save mode param is for PPAPI. 'Save As...' or downloading
|
||||
// something doesn't reach here. They show 'select file dialog' from
|
||||
// DownloadFilePicker::DownloadFilePicker directly.
|
||||
// https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/public/mojom/choosers/file_chooser.mojom;l=27;drc=047c7dc4ee1ce908d7fea38ca063fa2f80f92c77
|
||||
|
||||
new_params->title = brave::GetFileSelectTitle(
|
||||
content::WebContents::FromRenderFrameHost(render_frame_host),
|
||||
render_frame_host->GetLastCommittedOrigin(),
|
||||
params.mode == blink::mojom::FileChooserParams::Mode::kSave
|
||||
? brave::FileSelectTitleType::kSave
|
||||
: brave::FileSelectTitleType::kOpen);
|
||||
}
|
||||
Browser::RunFileChooser(render_frame_host, listener, *new_params);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool BraveBrowser::ShouldDisplayFavicon(
|
||||
content::WebContents* web_contents) const {
|
||||
// Override to not show favicon for NTP in tab.
|
||||
|
||||
@@ -54,6 +54,10 @@ class BraveBrowser : public Browser {
|
||||
void OnTabClosing(content::WebContents* contents) override;
|
||||
void TabStripEmpty() override;
|
||||
|
||||
void RunFileChooser(content::RenderFrameHost* render_frame_host,
|
||||
scoped_refptr<content::FileSelectListener> listener,
|
||||
const blink::mojom::FileChooserParams& params) override;
|
||||
|
||||
// Returns true when we should ask browser closing to users before handling
|
||||
// any warning/onbeforeunload handlers.
|
||||
bool ShouldAskForBrowserClosingBeforeHandlers();
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
/* Copyright (c) 2024 The Brave Authors. All rights reserved.
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "brave/browser/ui/brave_file_select_utils.h"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include "base/i18n/rtl.h"
|
||||
#include "base/no_destructor.h"
|
||||
#include "brave/grit/brave_generated_resources.h"
|
||||
#include "chrome/browser/profiles/profile.h"
|
||||
#include "chrome/browser/ui/url_identity.h"
|
||||
#include "components/strings/grit/components_strings.h"
|
||||
#include "components/url_formatter/elide_url.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
#include "ui/base/l10n/l10n_util.h"
|
||||
#include "url/gurl.h"
|
||||
#include "url/origin.h"
|
||||
|
||||
namespace brave {
|
||||
|
||||
namespace {
|
||||
|
||||
// If an origin is opaque but has a precursor, then returns the precursor
|
||||
// origin. If the origin is not opaque, returns it unchanged. Unwrapping origins
|
||||
// allows the dialog code to provide the user with a clearer picture of which
|
||||
// page is actually showing the dialog.
|
||||
url::Origin UnwrapOriginIfOpaque(const url::Origin& origin) {
|
||||
if (!origin.opaque()) {
|
||||
return origin;
|
||||
}
|
||||
|
||||
const url::SchemeHostPort& precursor =
|
||||
origin.GetTupleOrPrecursorTupleIfOpaque();
|
||||
if (!precursor.IsValid()) {
|
||||
return origin;
|
||||
}
|
||||
|
||||
return url::Origin::CreateFromNormalizedTuple(
|
||||
precursor.scheme(), precursor.host(), precursor.port());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
std::u16string GetFileSelectTitle(content::WebContents* web_contents,
|
||||
const url::Origin& alerting_frame_origin,
|
||||
FileSelectTitleType file_select_type) {
|
||||
// This implementation partially mirrors
|
||||
// ChromeAppModalDialogManagerDelegate::GetTitle().
|
||||
// TODO(sko) It's hard to test this behavior is in sync at this moment. Even
|
||||
// upstream tests aren't covering this. Need to figure out how we can test
|
||||
// extension and isolated web app case.
|
||||
Profile* profile =
|
||||
Profile::FromBrowserContext(web_contents->GetBrowserContext());
|
||||
|
||||
UrlIdentity url_identity = UrlIdentity::CreateFromUrl(
|
||||
profile, alerting_frame_origin.GetURL(),
|
||||
/*allowed_types*/
|
||||
{UrlIdentity::Type::kDefault, UrlIdentity::Type::kFile,
|
||||
UrlIdentity::Type::kIsolatedWebApp, UrlIdentity::Type::kChromeExtension},
|
||||
/*default_options*/ {.default_options = {}});
|
||||
|
||||
if (url_identity.type == UrlIdentity::Type::kChromeExtension) {
|
||||
return url_identity.name;
|
||||
}
|
||||
|
||||
if (url_identity.type == UrlIdentity::Type::kIsolatedWebApp) {
|
||||
return url_identity.name;
|
||||
}
|
||||
|
||||
const auto main_frame_origin =
|
||||
web_contents->GetPrimaryMainFrame()->GetLastCommittedOrigin();
|
||||
return GetSiteFrameTitleForFileSelect(
|
||||
GetSiteFrameTitleType(main_frame_origin, alerting_frame_origin),
|
||||
alerting_frame_origin, file_select_type);
|
||||
}
|
||||
|
||||
std::u16string GetSiteFrameTitleForFileSelect(
|
||||
SiteFrameTitleType frame_type,
|
||||
const url::Origin& alerting_frame_origin,
|
||||
FileSelectTitleType file_select_type) {
|
||||
constexpr std::array<
|
||||
std::array<int, static_cast<size_t>(SiteFrameTitleType::kSize)>,
|
||||
static_cast<size_t>(FileSelectTitleType::kSize)>
|
||||
kResourceIDs = {
|
||||
{/*FileSelectTitleType::kOpen,*/
|
||||
{
|
||||
IDS_BRAVE_FILE_SELECT_OPEN_TITLE, // brave::SiteFrameTitleType::kStandardSameOrigin
|
||||
IDS_BRAVE_FILE_SELECT_OPEN_TITLE_IFRAME, // brave::SiteFrameTitleType::kStandardDifferentOrigin
|
||||
IDS_BRAVE_FILE_SELECT_OPEN_TITLE_NONSTANDARD_URL, // brave::SiteFrameTitleType::kNonStandardSameOrigin
|
||||
IDS_BRAVE_FILE_SELECT_OPEN_TITLE_NONSTANDARD_URL_IFRAME // brave::SiteFrameTitleType::kNonStandardDifferentOrigin
|
||||
},
|
||||
/*FileSelectTitleType::kSave,*/
|
||||
{
|
||||
IDS_BRAVE_FILE_SELECT_SAVE_TITLE, // brave::SiteFrameTitleType::kStandardSameOrigin
|
||||
IDS_BRAVE_FILE_SELECT_SAVE_TITLE_IFRAME, // brave::SiteFrameTitleType::kStandardDifferentOrigin
|
||||
IDS_BRAVE_FILE_SELECT_SAVE_TITLE_NONSTANDARD_URL, // brave::SiteFrameTitleType::kNonStandardSameOrigin
|
||||
IDS_BRAVE_FILE_SELECT_SAVE_TITLE_NONSTANDARD_URL_IFRAME // brave::SiteFrameTitleType::kNonStandardDifferentOrigin
|
||||
},
|
||||
/*FileSelectTitleType::kChromiumDefault*/
|
||||
{
|
||||
IDS_JAVASCRIPT_MESSAGEBOX_TITLE, // brave::SiteFrameTitleType::kStandardSameOrigin
|
||||
IDS_JAVASCRIPT_MESSAGEBOX_TITLE_IFRAME, // brave::SiteFrameTitleType::kStandardDifferentOrigin,
|
||||
IDS_JAVASCRIPT_MESSAGEBOX_TITLE_NONSTANDARD_URL, // brave::SiteFrameTitleType::kNonStandardSameOrigin
|
||||
IDS_JAVASCRIPT_MESSAGEBOX_TITLE_NONSTANDARD_URL_IFRAME, // brave::SiteFrameTitleType::kNonStandardDifferentOrigin,
|
||||
}}};
|
||||
|
||||
if (frame_type == SiteFrameTitleType::kStandardSameOrigin ||
|
||||
frame_type == SiteFrameTitleType::kStandardDifferentOrigin) {
|
||||
std::u16string origin_string =
|
||||
url_formatter::FormatOriginForSecurityDisplay(
|
||||
UnwrapOriginIfOpaque(alerting_frame_origin),
|
||||
url_formatter::SchemeDisplay::OMIT_HTTP_AND_HTTPS);
|
||||
return l10n_util::GetStringFUTF16(
|
||||
kResourceIDs[static_cast<size_t>(file_select_type)]
|
||||
[static_cast<size_t>(frame_type)],
|
||||
base::i18n::GetDisplayStringInLTRDirectionality(origin_string));
|
||||
}
|
||||
|
||||
return l10n_util::GetStringUTF16(kResourceIDs[static_cast<size_t>(
|
||||
file_select_type)][static_cast<size_t>(frame_type)]);
|
||||
}
|
||||
|
||||
SiteFrameTitleType GetSiteFrameTitleType(
|
||||
const url::Origin& main_frame_origin,
|
||||
const url::Origin& alerting_frame_origin) {
|
||||
// This implementation mirrors `AppModalDialogManager::GetSiteFrameTitle()`.
|
||||
// We have a test to check if the two implementations are in sync.
|
||||
// - BraveFileSelectHelperUnitTest.GetSiteFrameTitleType_InSyncWithUpstream.
|
||||
const url::Origin unwrapped_main_frame_origin =
|
||||
UnwrapOriginIfOpaque(main_frame_origin);
|
||||
const url::Origin unwrapped_alerting_frame_origin =
|
||||
UnwrapOriginIfOpaque(alerting_frame_origin);
|
||||
|
||||
const bool is_same_origin_as_main_frame =
|
||||
unwrapped_alerting_frame_origin.IsSameOriginWith(
|
||||
unwrapped_main_frame_origin);
|
||||
if (unwrapped_alerting_frame_origin.GetURL().IsStandard() &&
|
||||
!unwrapped_alerting_frame_origin.GetURL().SchemeIsFile()) {
|
||||
return is_same_origin_as_main_frame
|
||||
? SiteFrameTitleType::kStandardSameOrigin
|
||||
: SiteFrameTitleType::kStandardDifferentOrigin;
|
||||
}
|
||||
return is_same_origin_as_main_frame
|
||||
? SiteFrameTitleType::kNonStandardSameOrigin
|
||||
: SiteFrameTitleType::kNonStandardDifferentOrigin;
|
||||
}
|
||||
|
||||
} // namespace brave
|
||||
@@ -0,0 +1,63 @@
|
||||
/* Copyright (c) 2024 The Brave Authors. All rights reserved.
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef BRAVE_BROWSER_UI_BRAVE_FILE_SELECT_UTILS_H_
|
||||
#define BRAVE_BROWSER_UI_BRAVE_FILE_SELECT_UTILS_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/containers/flat_map.h"
|
||||
|
||||
namespace content {
|
||||
class WebContents;
|
||||
} // namespace content
|
||||
|
||||
namespace url {
|
||||
class Origin;
|
||||
} // namespace url
|
||||
|
||||
namespace brave {
|
||||
|
||||
// This enum values are used to determine the title of the file select dialog.
|
||||
// Basically it mirrors std::u16string
|
||||
// AppModalDialogManager::GetSiteFrameTitle() implementation.
|
||||
enum class SiteFrameTitleType {
|
||||
kStandardSameOrigin, // alerting frame has http(s) scheme and has the same
|
||||
// origin with main frame
|
||||
kStandardDifferentOrigin, // alerting frame http(s) scheme and has a
|
||||
// different origin with main frame
|
||||
kNonStandardSameOrigin, // alerting frame has other schemes (e.g. file,
|
||||
// data, javascript) and has the same origin with
|
||||
// main frame
|
||||
kNonStandardDifferentOrigin, // alerting frame has other schemes (e.g. file,
|
||||
// data, javascript) and has a different origin
|
||||
// with main frame
|
||||
kSize
|
||||
};
|
||||
|
||||
enum class FileSelectTitleType {
|
||||
kOpen,
|
||||
kSave,
|
||||
kChromiumDefault, // used for comparing with the default title of the file
|
||||
// select dialog in Chromium
|
||||
kSize
|
||||
};
|
||||
|
||||
std::u16string GetFileSelectTitle(content::WebContents* contents,
|
||||
const url::Origin& alerting_frame_origin,
|
||||
FileSelectTitleType file_select_type);
|
||||
|
||||
std::u16string GetSiteFrameTitleForFileSelect(
|
||||
SiteFrameTitleType frame_type,
|
||||
const url::Origin& alerting_frame_origin,
|
||||
FileSelectTitleType select_type);
|
||||
|
||||
SiteFrameTitleType GetSiteFrameTitleType(
|
||||
const url::Origin& main_frame_origin,
|
||||
const url::Origin& alerting_frame_origin);
|
||||
|
||||
} // namespace brave
|
||||
|
||||
#endif // BRAVE_BROWSER_UI_BRAVE_FILE_SELECT_UTILS_H_
|
||||
@@ -0,0 +1,309 @@
|
||||
/* Copyright (c) 2024 The Brave Authors. All rights reserved.
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "brave/browser/ui/brave_file_select_utils.h"
|
||||
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "brave/components/l10n/common/test/scoped_default_locale.h"
|
||||
#include "components/javascript_dialogs/app_modal_dialog_manager.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
#include "url/origin.h"
|
||||
|
||||
TEST(BraveFileSelectUtilsUnitTest, GetSiteFrameTitle_InSyncWithUpstream) {
|
||||
constexpr struct Case {
|
||||
// The name of the test case.
|
||||
const char* case_name;
|
||||
|
||||
// The URL of the main frame of the page.
|
||||
const char* main_frame_url;
|
||||
|
||||
// Whether the main frame is alerting.
|
||||
bool is_main_frame;
|
||||
|
||||
// If `is_main_frame` is false, the URL of the alerting frame of the page.
|
||||
const char* alerting_frame_url;
|
||||
} kCases[] = {
|
||||
// Standard main frame alert.
|
||||
{"standard", "http://foo.com/", true, ""},
|
||||
|
||||
// Subframe alert from the same origin.
|
||||
{"subframe same origin", "http://foo.com/1", false, "http://foo.com/2"},
|
||||
// Subframe alert from a different origin.
|
||||
{"subframe different origin", "http://foo.com/", false,
|
||||
"http://bar.com/"},
|
||||
|
||||
// file:
|
||||
// - main frame:
|
||||
{"file main frame", "file:///path/to/page.html", true, ""},
|
||||
// - subframe:
|
||||
{"file subframe", "http://foo.com/", false, "file:///path/to/page.html"},
|
||||
|
||||
// data:
|
||||
// /!\ NOTE that this is for data URLs entered directly in the omnibox.
|
||||
// For pages that generate frames with data URLs, see the browsertest.
|
||||
// - main frame:
|
||||
{"data main frame", "data:blahblah", true, ""},
|
||||
// - subframe:
|
||||
{"data subframe", "http://foo.com/", false, "data:blahblah"},
|
||||
|
||||
// javascript:
|
||||
// /!\ NOTE that this is for javascript URLs entered directly in the
|
||||
// omnibox. For pages that generate frames with javascript URLs, see the
|
||||
// browsertest.
|
||||
// - main frame:
|
||||
{"javascript main frame", "javascript:abc", true, ""},
|
||||
// - subframe:
|
||||
{"javascript subframe", "http://foo.com/", false, "javascript:abc"},
|
||||
|
||||
// about:
|
||||
// /!\ NOTE that this is for about:blank URLs entered directly in the
|
||||
// omnibox. For pages that generate frames with about:blank URLs, see the
|
||||
// browsertest.
|
||||
// - main frame:
|
||||
{"about main frame", "about:blank", true, ""},
|
||||
// - subframe:
|
||||
{"about subframe", "http://foo.com/", false, "about:blank"},
|
||||
|
||||
// blob:
|
||||
// - main frame:
|
||||
{"blob main frame",
|
||||
"blob:http://foo.com/66666666-6666-6666-6666-666666666666", true, ""},
|
||||
// - subframe:
|
||||
{"blob subframe", "http://bar.com/", false,
|
||||
"blob:http://foo.com/66666666-6666-6666-6666-666666666666"},
|
||||
|
||||
// filesystem:
|
||||
// - main frame:
|
||||
{"filesystem main frame", "filesystem:http://foo.com/bar.html", true, ""},
|
||||
// - subframe:
|
||||
{"filesystem subframe", "http://bar.com/", false,
|
||||
"filesystem:http://foo.com/bar.html"},
|
||||
};
|
||||
// Checks if our implementation is in sync with upstream.
|
||||
|
||||
for (const auto& test_case : kCases) {
|
||||
SCOPED_TRACE(test_case.case_name);
|
||||
|
||||
url::Origin main_frame_origin =
|
||||
url::Origin::Create(GURL(test_case.main_frame_url));
|
||||
url::Origin alerting_frame_origin =
|
||||
test_case.is_main_frame
|
||||
? main_frame_origin
|
||||
: url::Origin::Create(GURL(test_case.alerting_frame_url));
|
||||
EXPECT_EQ(javascript_dialogs::AppModalDialogManager::GetSiteFrameTitle(
|
||||
main_frame_origin, alerting_frame_origin),
|
||||
brave::GetSiteFrameTitleForFileSelect(
|
||||
brave::GetSiteFrameTitleType(main_frame_origin,
|
||||
alerting_frame_origin),
|
||||
alerting_frame_origin,
|
||||
brave::FileSelectTitleType::kChromiumDefault));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(BraveFileSelectUtilsUnitTest, GetSiteFrameTitleForFileSelect_Open) {
|
||||
constexpr struct Case {
|
||||
// The name of the test case.
|
||||
const char* case_name;
|
||||
|
||||
// The URL of the main frame of the page.
|
||||
const char* main_frame_url;
|
||||
|
||||
// Whether the main frame is alerting.
|
||||
bool is_main_frame;
|
||||
|
||||
// If `is_main_frame` is false, the URL of the alerting frame of the page.
|
||||
const char* alerting_frame_url;
|
||||
|
||||
// The expected title for the alert.
|
||||
const char* expected;
|
||||
} kCases[] = {
|
||||
// Standard main frame alert.
|
||||
{"standard", "http://foo.com/", true, "", "foo.com wants to open"},
|
||||
|
||||
// Subframe alert from the same origin.
|
||||
{"subframe same origin", "http://foo.com/1", false, "http://foo.com/2",
|
||||
"foo.com wants to open"},
|
||||
// Subframe alert from a different origin.
|
||||
{"subframe different origin", "http://foo.com/", false, "http://bar.com/",
|
||||
"An embedded page on bar.com wants to open"},
|
||||
|
||||
// file:
|
||||
// - main frame:
|
||||
{"file main frame", "file:///path/to/page.html", true, "",
|
||||
"This page wants to open"},
|
||||
// - subframe:
|
||||
{"file subframe", "http://foo.com/", false, "file:///path/to/page.html",
|
||||
"An embedded page on this page wants to open"},
|
||||
|
||||
// data:
|
||||
// /!\ NOTE that this is for data URLs entered directly in the omnibox.
|
||||
// For pages that generate frames with data URLs, see the browsertest.
|
||||
// - main frame:
|
||||
{"data main frame", "data:blahblah", true, "", "This page wants to open"},
|
||||
// - subframe:
|
||||
{"data subframe", "http://foo.com/", false, "data:blahblah",
|
||||
"An embedded page on this page wants to open"},
|
||||
|
||||
// javascript:
|
||||
// /!\ NOTE that this is for javascript URLs entered directly in the
|
||||
// omnibox. For pages that generate frames with javascript URLs, see the
|
||||
// browsertest.
|
||||
// - main frame:
|
||||
{"javascript main frame", "javascript:abc", true, "",
|
||||
"This page wants to open"},
|
||||
// - subframe:
|
||||
{"javascript subframe", "http://foo.com/", false, "javascript:abc",
|
||||
"An embedded page on this page wants to open"},
|
||||
|
||||
// about:
|
||||
// /!\ NOTE that this is for about:blank URLs entered directly in the
|
||||
// omnibox. For pages that generate frames with about:blank URLs, see the
|
||||
// browsertest.
|
||||
// - main frame:
|
||||
{"about main frame", "about:blank", true, "", "This page wants to open"},
|
||||
// - subframe:
|
||||
{"about subframe", "http://foo.com/", false, "about:blank",
|
||||
"An embedded page on this page wants to open"},
|
||||
|
||||
// blob:
|
||||
// - main frame:
|
||||
{"blob main frame",
|
||||
"blob:http://foo.com/66666666-6666-6666-6666-666666666666", true, "",
|
||||
"foo.com wants to open"},
|
||||
// - subframe:
|
||||
{"blob subframe", "http://bar.com/", false,
|
||||
"blob:http://foo.com/66666666-6666-6666-6666-666666666666",
|
||||
"An embedded page on foo.com wants to open"},
|
||||
|
||||
// filesystem:
|
||||
// - main frame:
|
||||
{"filesystem main frame", "filesystem:http://foo.com/bar.html", true, "",
|
||||
"foo.com wants to open"},
|
||||
// - subframe:
|
||||
{"filesystem subframe", "http://bar.com/", false,
|
||||
"filesystem:http://foo.com/bar.html",
|
||||
"An embedded page on foo.com wants to open"},
|
||||
};
|
||||
|
||||
brave_l10n::test::ScopedDefaultLocale scoped_locale("en-US");
|
||||
|
||||
for (const auto& test_case : kCases) {
|
||||
SCOPED_TRACE(test_case.case_name);
|
||||
url::Origin main_frame_origin =
|
||||
url::Origin::Create(GURL(test_case.main_frame_url));
|
||||
url::Origin alerting_frame_origin =
|
||||
test_case.is_main_frame
|
||||
? main_frame_origin
|
||||
: url::Origin::Create(GURL(test_case.alerting_frame_url));
|
||||
EXPECT_EQ(base::UTF8ToUTF16(test_case.expected),
|
||||
brave::GetSiteFrameTitleForFileSelect(
|
||||
brave::GetSiteFrameTitleType(main_frame_origin,
|
||||
alerting_frame_origin),
|
||||
alerting_frame_origin, brave::FileSelectTitleType::kOpen));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(BraveFileSelectUtilsUnitTest, GetSiteFrameTitleForFileSelect_Save) {
|
||||
constexpr struct Case {
|
||||
// The name of the test case.
|
||||
const char* case_name;
|
||||
|
||||
// The URL of the main frame of the page.
|
||||
const char* main_frame_url;
|
||||
|
||||
// Whether the main frame is alerting.
|
||||
bool is_main_frame;
|
||||
|
||||
// If `is_main_frame` is false, the URL of the alerting frame of the page.
|
||||
const char* alerting_frame_url;
|
||||
|
||||
// The expected title for the alert.
|
||||
const char* expected;
|
||||
} kCases[] = {
|
||||
// Standard main frame alert.
|
||||
{"standard", "http://foo.com/", true, "", "foo.com wants to save"},
|
||||
|
||||
// Subframe alert from the same origin.
|
||||
{"subframe same origin", "http://foo.com/1", false, "http://foo.com/2",
|
||||
"foo.com wants to save"},
|
||||
// Subframe alert from a different origin.
|
||||
{"subframe different origin", "http://foo.com/", false, "http://bar.com/",
|
||||
"An embedded page on bar.com wants to save"},
|
||||
|
||||
// file:
|
||||
// - main frame:
|
||||
{"file main frame", "file:///path/to/page.html", true, "",
|
||||
"This page wants to save"},
|
||||
// - subframe:
|
||||
{"file subframe", "http://foo.com/", false, "file:///path/to/page.html",
|
||||
"An embedded page on this page wants to save"},
|
||||
|
||||
// data:
|
||||
// /!\ NOTE that this is for data URLs entered directly in the omnibox.
|
||||
// For pages that generate frames with data URLs, see the browsertest.
|
||||
// - main frame:
|
||||
{"data main frame", "data:blahblah", true, "", "This page wants to save"},
|
||||
// - subframe:
|
||||
{"data subframe", "http://foo.com/", false, "data:blahblah",
|
||||
"An embedded page on this page wants to save"},
|
||||
|
||||
// javascript:
|
||||
// /!\ NOTE that this is for javascript URLs entered directly in the
|
||||
// omnibox. For pages that generate frames with javascript URLs, see the
|
||||
// browsertest.
|
||||
// - main frame:
|
||||
{"javascript main frame", "javascript:abc", true, "",
|
||||
"This page wants to save"},
|
||||
// - subframe:
|
||||
{"javascript subframe", "http://foo.com/", false, "javascript:abc",
|
||||
"An embedded page on this page wants to save"},
|
||||
|
||||
// about:
|
||||
// /!\ NOTE that this is for about:blank URLs entered directly in the
|
||||
// omnibox. For pages that generate frames with about:blank URLs, see the
|
||||
// browsertest.
|
||||
// - main frame:
|
||||
{"about main frame", "about:blank", true, "", "This page wants to save"},
|
||||
// - subframe:
|
||||
{"about subframe", "http://foo.com/", false, "about:blank",
|
||||
"An embedded page on this page wants to save"},
|
||||
|
||||
// blob:
|
||||
// - main frame:
|
||||
{"blob main frame",
|
||||
"blob:http://foo.com/66666666-6666-6666-6666-666666666666", true, "",
|
||||
"foo.com wants to save"},
|
||||
// - subframe:
|
||||
{"blob subframe", "http://bar.com/", false,
|
||||
"blob:http://foo.com/66666666-6666-6666-6666-666666666666",
|
||||
"An embedded page on foo.com wants to save"},
|
||||
|
||||
// filesystem:
|
||||
// - main frame:
|
||||
{"filesystem main frame", "filesystem:http://foo.com/bar.html", true, "",
|
||||
"foo.com wants to save"},
|
||||
// - subframe:
|
||||
{"filesystem subframe", "http://bar.com/", false,
|
||||
"filesystem:http://foo.com/bar.html",
|
||||
"An embedded page on foo.com wants to save"},
|
||||
};
|
||||
|
||||
brave_l10n::test::ScopedDefaultLocale scoped_locale("en-US");
|
||||
|
||||
for (const auto& test_case : kCases) {
|
||||
SCOPED_TRACE(test_case.case_name);
|
||||
url::Origin main_frame_origin =
|
||||
url::Origin::Create(GURL(test_case.main_frame_url));
|
||||
url::Origin alerting_frame_origin =
|
||||
test_case.is_main_frame
|
||||
? main_frame_origin
|
||||
: url::Origin::Create(GURL(test_case.alerting_frame_url));
|
||||
EXPECT_EQ(base::UTF8ToUTF16(test_case.expected),
|
||||
brave::GetSiteFrameTitleForFileSelect(
|
||||
brave::GetSiteFrameTitleType(main_frame_origin,
|
||||
alerting_frame_origin),
|
||||
alerting_frame_origin, brave::FileSelectTitleType::kSave));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/* Copyright (c) 2024 The Brave Authors. All rights reserved.
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "content/public/browser/render_frame_host.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
#include "third_party/blink/public/mojom/choosers/file_chooser.mojom.h"
|
||||
#include "ui/shell_dialogs/select_file_dialog.h"
|
||||
|
||||
#if !BUILDFLAG(IS_ANDROID)
|
||||
#include "brave/browser/ui/brave_file_select_utils.h"
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
std::u16string GetTitle(content::RenderFrameHost* render_frame_host,
|
||||
const std::u16string& original_title) {
|
||||
#if BUILDFLAG(IS_ANDROID)
|
||||
return original_title;
|
||||
#else
|
||||
return brave::GetFileSelectTitle(
|
||||
content::WebContents::FromRenderFrameHost(render_frame_host),
|
||||
render_frame_host->GetLastCommittedOrigin(),
|
||||
brave::FileSelectTitleType::kSave);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// Override title of the file select dialog for downloads.
|
||||
#define SelectFile(type, title, default_path, file_types, file_type_index, \
|
||||
default_extension, owning_window, params, caller) \
|
||||
SelectFile(type, GetTitle(render_frame_host, title), default_path, \
|
||||
file_types, file_type_index, default_extension, owning_window, \
|
||||
params, caller)
|
||||
|
||||
#include "src/chrome/browser/download/download_file_picker.cc"
|
||||
|
||||
#undef SelectFile
|
||||
@@ -0,0 +1,31 @@
|
||||
/* Copyright (c) 2024 The Brave Authors. All rights reserved.
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// Can be removed once
|
||||
// https://chromium-review.googlesource.com/c/chromium/src/+/5711152 arrives in
|
||||
// Brave.
|
||||
#define BRAVE_EXECUTE_SELECT_SINGLE_FILE \
|
||||
return RunOpenFileDialog(owner, title, std::u16string(), default_path, \
|
||||
filter, 0, filter_index, paths);
|
||||
|
||||
// Can be removed once
|
||||
// https://chromium-review.googlesource.com/c/chromium/src/+/5711152 arrives in
|
||||
// Brave.
|
||||
#define BRAVE_EXECUTE_SELECT_MULTIPLE_FILE \
|
||||
return RunOpenFileDialog(owner, title, std::u16string(), default_path, \
|
||||
filter, dialog_options, filter_index, paths);
|
||||
|
||||
// Can be removed once
|
||||
// https://chromium-review.googlesource.com/c/chromium/src/+/5711152 arrives in
|
||||
// Brave.
|
||||
#define BRAVE_EXECUTE_SAVE_FILE \
|
||||
return RunSaveFileDialog(owner, title, default_path, filter, dialog_options, \
|
||||
def_ext, filter_index, path);
|
||||
|
||||
#include "src/ui/shell_dialogs/execute_select_file_win.cc"
|
||||
|
||||
#undef BRAVE_EXECUTE_SAVE_FILE
|
||||
#undef BRAVE_EXECUTE_SELECT_MULTIPLE_FILE
|
||||
#undef BRAVE_EXECUTE_SELECT_SINGLE_FILE
|
||||
@@ -0,0 +1,44 @@
|
||||
diff --git a/ui/shell_dialogs/execute_select_file_win.cc b/ui/shell_dialogs/execute_select_file_win.cc
|
||||
index 5ef377bcbd69f2f2160aeed6ec4aa9fe3f20275c..ef56ddbe38b42410d7d6571796e025f3059c9c1a 100644
|
||||
--- a/ui/shell_dialogs/execute_select_file_win.cc
|
||||
+++ b/ui/shell_dialogs/execute_select_file_win.cc
|
||||
@@ -362,6 +362,7 @@ bool ExecuteSelectSingleFile(HWND owner,
|
||||
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.
|
||||
+ BRAVE_EXECUTE_SELECT_SINGLE_FILE
|
||||
return RunOpenFileDialog(owner, std::u16string(), std::u16string(),
|
||||
default_path, filter, 0, filter_index, paths);
|
||||
}
|
||||
@@ -376,12 +377,14 @@ bool ExecuteSelectMultipleFile(HWND owner,
|
||||
|
||||
// Note: The title is not passed down for historical reasons.
|
||||
// TODO(pmonette): Figure out if it's a worthwhile improvement.
|
||||
+ BRAVE_EXECUTE_SELECT_MULTIPLE_FILE
|
||||
return RunOpenFileDialog(owner, std::u16string(), 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,
|
||||
@@ -396,6 +399,7 @@ bool ExecuteSaveFile(HWND owner,
|
||||
|
||||
// Note: The title is not passed down for historical reasons.
|
||||
// TODO(pmonette): Figure out if it's a worthwhile improvement.
|
||||
+ BRAVE_EXECUTE_SAVE_FILE
|
||||
return RunSaveFileDialog(owner, std::u16string(), default_path, filter,
|
||||
dialog_options, def_ext, filter_index, path);
|
||||
}
|
||||
@@ -421,7 +425,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));
|
||||
}
|
||||
Reference in New Issue
Block a user