#include "content/browser/web_contents/web_contents_view_aura.h"
#include <memory>
#include <optional>
#include <string>
#include "base/command_line.h"
#include "base/files/file_util.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/scoped_command_line.h"
#include "base/test/scoped_feature_list.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/browser/web_contents_delegate.h"
#include "content/public/common/content_features.h"
#include "content/public/test/test_renderer_host.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/client/drag_drop_client.h"
#include "ui/aura/test/test_windows.h"
#include "ui/aura/test/window_test_api.h"
#include "ui/aura/window.h"
#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
#include "ui/base/dragdrop/drag_drop_types.h"
#include "ui/base/dragdrop/drop_target_event.h"
#include "ui/base/dragdrop/mojom/drag_drop_types.mojom.h"
#include "ui/base/dragdrop/os_exchange_data.h"
#include "ui/base/ozone_buildflags.h"
#include "ui/display/display_switches.h"
#include "ui/events/base_event_utils.h"
#include "ui/gfx/geometry/rect.h"
#include "url/origin.h"
#if BUILDFLAG(IS_WIN)
#include "ui/base/dragdrop/os_exchange_data_provider_win.h"
#endif
#if BUILDFLAG(IS_LINUX) && BUILDFLAG(IS_OZONE_X11)
#include "ui/base/x/selection_utils.h"
#include "ui/base/x/x11_os_exchange_data_provider.h"
#include "ui/gfx/x/atom_cache.h"
#include "ui/gfx/x/connection.h"
#include "ui/ozone/public/ozone_platform.h"
#endif
namespace content {
namespace {
DragOperation;
constexpr gfx::Rect kBounds = …;
constexpr gfx::PointF kClientPt = …;
constexpr gfx::PointF kScreenPt = …;
class RunCallbackOnActivation : public WebContentsDelegate { … };
class PrivilegedWebContentsDelegate : public WebContentsDelegate { … };
class TestDragDropClient : public aura::client::DragDropClient { … };
}
class WebContentsViewAuraTest : public RenderViewHostTestHarness { … };
TEST_F(WebContentsViewAuraTest, EnableDisableOverscroll) { … }
TEST_F(WebContentsViewAuraTest, ShowHideParent) { … }
TEST_F(WebContentsViewAuraTest, WebContentsDestroyedDuringClick) { … }
TEST_F(WebContentsViewAuraTest, OccludeView) { … }
#if BUILDFLAG(IS_FUCHSIA)
#define MAYBE_DragDropFiles …
#define MAYBE_DragDropFilesOriginateFromRenderer …
#define MAYBE_DragDropImageFromRenderer …
#else
#define MAYBE_DragDropFiles …
#define MAYBE_DragDropFilesOriginateFromRenderer …
#define MAYBE_DragDropImageFromRenderer …
#endif
TEST_F(WebContentsViewAuraTest, MAYBE_DragDropFiles) { … }
TEST_F(WebContentsViewAuraTest, MAYBE_DragDropFilesOriginateFromRenderer) { … }
TEST_F(WebContentsViewAuraTest, MAYBE_DragDropImageFromRenderer) { … }
#if BUILDFLAG(IS_WIN)
TEST_F(WebContentsViewAuraTest, DragDropVirtualFiles) {
WebContentsViewAura* view = GetView();
auto data = std::make_unique<ui::OSExchangeData>();
const std::u16string string_data = u"Some string data";
data->SetString(string_data);
const std::vector<std::pair<base::FilePath, std::string>>
test_filenames_and_contents = {
{base::FilePath(FILE_PATH_LITERAL("filename.txt")),
std::string("just some data")},
{base::FilePath(FILE_PATH_LITERAL("another filename.txt")),
std::string("just some data\0with\0nulls", 25)},
{base::FilePath(FILE_PATH_LITERAL("and another filename.txt")),
std::string("just some more data")},
};
data->provider().SetVirtualFileContentsForTesting(test_filenames_and_contents,
TYMED_ISTREAM);
ui::DropTargetEvent event(*data.get(), kClientPt, kScreenPt,
ui::DragDropTypes::DRAG_COPY);
EXPECT_EQ(nullptr, view->current_drag_data_);
view->OnDragEntered(event);
ASSERT_NE(nullptr, view->current_drag_data_);
EXPECT_EQ(string_data, view->current_drag_data_->text);
const base::FilePath path_placeholder(FILE_PATH_LITERAL("temp.tmp"));
std::vector<ui::FileInfo> retrieved_file_infos =
view->current_drag_data_->filenames;
ASSERT_EQ(test_filenames_and_contents.size(), retrieved_file_infos.size());
for (size_t i = 0; i < retrieved_file_infos.size(); i++) {
EXPECT_EQ(test_filenames_and_contents[i].first,
retrieved_file_infos[i].display_name);
EXPECT_EQ(path_placeholder, retrieved_file_infos[i].path);
}
auto callback = base::BindOnce(&WebContentsViewAuraTest::OnDropComplete,
base::Unretained(this));
view->RegisterDropCallbackForTesting(std::move(callback));
base::RunLoop run_loop;
async_drop_closure_ = run_loop.QuitClosure();
auto drop_cb = view->GetDropCallback(event);
ASSERT_TRUE(drop_cb);
ui::mojom::DragOperation output_drag_op = ui::mojom::DragOperation::kNone;
std::move(drop_cb).Run(std::move(data), output_drag_op,
nullptr);
run_loop.Run();
CheckDropData(view);
EXPECT_EQ(string_data, drop_complete_data_->drop_data.text);
std::string read_contents;
base::FilePath temp_dir;
EXPECT_TRUE(base::GetTempDir(&temp_dir));
retrieved_file_infos = drop_complete_data_->drop_data.filenames;
ASSERT_EQ(test_filenames_and_contents.size(), retrieved_file_infos.size());
for (size_t i = 0; i < retrieved_file_infos.size(); i++) {
EXPECT_EQ(test_filenames_and_contents[i].first,
retrieved_file_infos[i].display_name);
EXPECT_EQ(base::MakeLongFilePath(temp_dir),
base::MakeLongFilePath(retrieved_file_infos[i].path.DirName()));
EXPECT_EQ(test_filenames_and_contents[i].first.Extension(),
retrieved_file_infos[i].path.Extension());
EXPECT_TRUE(
base::ReadFileToString(retrieved_file_infos[i].path, &read_contents));
EXPECT_EQ(test_filenames_and_contents[i].second, read_contents);
}
}
TEST_F(WebContentsViewAuraTest, DragDropVirtualFilesOriginateFromRenderer) {
WebContentsViewAura* view = GetView();
auto data = std::make_unique<ui::OSExchangeData>();
const std::u16string string_data = u"Some string data";
data->SetString(string_data);
const std::vector<std::pair<base::FilePath, std::string>>
test_filenames_and_contents = {
{base::FilePath(FILE_PATH_LITERAL("filename.txt")),
std::string("just some data")},
{base::FilePath(FILE_PATH_LITERAL("another filename.txt")),
std::string("just some data\0with\0nulls", 25)},
{base::FilePath(FILE_PATH_LITERAL("and another filename.txt")),
std::string("just some more data")},
};
data->provider().SetVirtualFileContentsForTesting(test_filenames_and_contents,
TYMED_ISTREAM);
data->MarkRendererTaintedFromOrigin(url::Origin());
ui::DropTargetEvent event(*data.get(), kClientPt, kScreenPt,
ui::DragDropTypes::DRAG_COPY);
EXPECT_EQ(nullptr, view->current_drag_data_);
view->OnDragEntered(event);
ASSERT_NE(nullptr, view->current_drag_data_);
EXPECT_EQ(string_data, view->current_drag_data_->text);
ASSERT_TRUE(view->current_drag_data_->filenames.empty());
auto callback = base::BindOnce(&WebContentsViewAuraTest::OnDropComplete,
base::Unretained(this));
view->RegisterDropCallbackForTesting(std::move(callback));
base::RunLoop run_loop;
async_drop_closure_ = run_loop.QuitClosure();
auto drop_cb = view->GetDropCallback(event);
ASSERT_TRUE(drop_cb);
ui::mojom::DragOperation output_drag_op = ui::mojom::DragOperation::kNone;
std::move(drop_cb).Run(std::move(data), output_drag_op,
nullptr);
run_loop.Run();
CheckDropData(view);
EXPECT_EQ(string_data, drop_complete_data_->drop_data.text);
ASSERT_TRUE(drop_complete_data_->drop_data.filenames.empty());
}
TEST_F(WebContentsViewAuraTest, DragDropUrlData) {
WebContentsViewAura* view = GetView();
auto data = std::make_unique<ui::OSExchangeData>();
data->MarkRendererTaintedFromOrigin(url::Origin());
const std::string url_spec = "https://www.wikipedia.org/";
const GURL url(url_spec);
const std::u16string url_title = u"Wikipedia";
data->SetURL(url, url_title);
std::optional<std::vector<ui::FileInfo>> file_infos =
data->GetVirtualFilenames();
ASSERT_TRUE(file_infos.has_value());
ASSERT_EQ(1ULL, file_infos.value().size());
EXPECT_EQ(base::FilePath(base::UTF16ToWide(url_title) + L".url"),
file_infos.value()[0].display_name);
ui::DropTargetEvent event(*data.get(), kClientPt, kScreenPt,
ui::DragDropTypes::DRAG_COPY);
EXPECT_EQ(nullptr, view->current_drag_data_);
view->OnDragEntered(event);
ASSERT_NE(nullptr, view->current_drag_data_);
EXPECT_EQ(url_spec, view->current_drag_data_->url);
EXPECT_EQ(url_title, view->current_drag_data_->url_title);
EXPECT_TRUE(view->current_drag_data_->filenames.empty());
EXPECT_TRUE(view->current_drag_data_->file_contents_source_url.is_empty());
EXPECT_TRUE(view->current_drag_data_->file_contents.empty());
auto callback = base::BindOnce(&WebContentsViewAuraTest::OnDropComplete,
base::Unretained(this));
view->RegisterDropCallbackForTesting(std::move(callback));
base::RunLoop run_loop;
async_drop_closure_ = run_loop.QuitClosure();
auto drop_cb = view->GetDropCallback(event);
ASSERT_TRUE(drop_cb);
ui::mojom::DragOperation output_drag_op = ui::mojom::DragOperation::kNone;
std::move(drop_cb).Run(std::move(data), output_drag_op,
nullptr);
run_loop.Run();
CheckDropData(view);
EXPECT_EQ(url_spec, drop_complete_data_->drop_data.url);
EXPECT_EQ(url_title, drop_complete_data_->drop_data.url_title);
EXPECT_TRUE(drop_complete_data_->drop_data.filenames.empty());
EXPECT_TRUE(
drop_complete_data_->drop_data.file_contents_source_url.is_empty());
EXPECT_TRUE(drop_complete_data_->drop_data.file_contents.empty());
}
#endif
#if BUILDFLAG(IS_CHROMEOS_ASH)
TEST_F(WebContentsViewAuraTest, StartDragging) {
const char kGmailUrl[] = "http://mail.google.com/";
NavigateAndCommit(GURL(kGmailUrl));
FocusWebContentsOnMainFrame();
TestDragDropClient drag_drop_client;
aura::client::SetDragDropClient(root_window(), &drag_drop_client);
WebContentsViewAura* view = GetView();
view->drag_in_progress_ = true;
DropData drop_data;
drop_data.text.emplace(u"Hello World!");
view->StartDragging(drop_data, url::Origin(),
blink::DragOperationsMask::kDragOperationNone,
gfx::ImageSkia(), gfx::Vector2d(), gfx::Rect(),
blink::mojom::DragEventSourceInfo(),
RenderWidgetHostImpl::From(rvh()->GetWidget()));
ui::OSExchangeData* exchange_data = drag_drop_client.GetDragDropData();
EXPECT_TRUE(exchange_data);
EXPECT_TRUE(exchange_data->GetSource());
EXPECT_TRUE(exchange_data->GetSource()->IsUrlType());
EXPECT_EQ(*(exchange_data->GetSource()->GetURL()), GURL(kGmailUrl));
}
#endif
TEST_F(WebContentsViewAuraTest,
RejectDragFromPrivilegedWebContentsToNonPrivilegedWebContents) { … }
TEST_F(WebContentsViewAuraTest,
AcceptDragFromPrivilegedWebContentsToPrivilegedWebContents) { … }
TEST_F(WebContentsViewAuraTest,
RejectDragFromNonPrivilegedWebContentsToPrivilegedWebContents) { … }
TEST_F(WebContentsViewAuraTest, StartDragFromPrivilegedWebContents) { … }
TEST_F(WebContentsViewAuraTest, EmptyTextInDropDataIsNonNullInOSExchangeData) { … }
TEST_F(WebContentsViewAuraTest,
EmptyTextWithUrlInDropDataIsEmptyInOSExchangeDataGetString) { … }
TEST_F(WebContentsViewAuraTest,
UrlInDropDataReturnsUrlInOSExchangeDataGetString) { … }
}