blob: 83403cb62c72f14df7f3d0e3de6effd01cd9ab18 [file] [log] [blame]
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/base/dragdrop/os_exchange_data_provider_non_backed.h"
#include <memory>
#include <optional>
#include <string>
#include <string_view>
#include "base/check.h"
#include "base/containers/contains.h"
#include "base/feature_list.h"
#include "base/files/file_path.h"
#include "base/strings/utf_string_conversions.h"
#include "net/base/filename_util.h"
#include "ui/base/clipboard/clipboard_format_type.h"
#include "ui/base/clipboard/file_info.h"
#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
#include "ui/base/dragdrop/os_exchange_data.h"
#include "ui/base/dragdrop/os_exchange_data_provider.h"
#include "ui/base/ui_base_features.h"
#include "url/gurl.h"
namespace ui {
OSExchangeDataProviderNonBacked::OSExchangeDataProviderNonBacked() = default;
OSExchangeDataProviderNonBacked::~OSExchangeDataProviderNonBacked() = default;
std::unique_ptr<OSExchangeDataProvider> OSExchangeDataProviderNonBacked::Clone()
const {
auto clone = std::make_unique<OSExchangeDataProviderNonBacked>();
CopyData(clone.get());
return clone;
}
void OSExchangeDataProviderNonBacked::MarkRendererTaintedFromOrigin(
const url::Origin& origin) {
tainted_by_renderer_origin_ = origin;
}
bool OSExchangeDataProviderNonBacked::IsRendererTainted() const {
return tainted_by_renderer_origin_.has_value();
}
std::optional<url::Origin>
OSExchangeDataProviderNonBacked::GetRendererTaintedOrigin() const {
// Platform-specific implementations of OSExchangeDataProvider do not
// roundtrip opaque origins, so match that behavior here.
if (tainted_by_renderer_origin_ && tainted_by_renderer_origin_->opaque()) {
return url::Origin();
}
return tainted_by_renderer_origin_;
}
void OSExchangeDataProviderNonBacked::MarkAsFromPrivileged() {
is_from_privileged_ = true;
}
bool OSExchangeDataProviderNonBacked::IsFromPrivileged() const {
return is_from_privileged_;
}
void OSExchangeDataProviderNonBacked::SetString(std::u16string_view data) {
if (HasString())
return;
string_ = std::u16string(data);
formats_ |= OSExchangeData::STRING;
}
void OSExchangeDataProviderNonBacked::SetURL(const GURL& url,
std::u16string_view title) {
url_ = url;
title_ = title;
formats_ |= OSExchangeData::URL;
SetString(base::UTF8ToUTF16(url.spec()));
}
void OSExchangeDataProviderNonBacked::SetFilename(const base::FilePath& path) {
filenames_.clear();
filenames_.push_back(FileInfo(path, base::FilePath()));
formats_ |= OSExchangeData::FILE_NAME;
}
void OSExchangeDataProviderNonBacked::SetFilenames(
const std::vector<FileInfo>& filenames) {
filenames_ = filenames;
formats_ |= OSExchangeData::FILE_NAME;
}
void OSExchangeDataProviderNonBacked::SetPickledData(
const ClipboardFormatType& format,
const base::Pickle& data) {
pickle_data_[format] = data;
formats_ |= OSExchangeData::PICKLED_DATA;
}
std::optional<std::u16string> OSExchangeDataProviderNonBacked::GetString()
const {
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
if (HasFile()) {
// Various Linux file managers both pass a list of file:// URIs and set the
// string representation to the URI. We explicitly don't want to return use
// this representation.
return std::nullopt;
}
#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
if ((formats_ & OSExchangeData::STRING) == 0)
return std::nullopt;
return string_;
}
std::optional<OSExchangeDataProvider::UrlInfo>
OSExchangeDataProviderNonBacked::GetURLAndTitle(
FilenameToURLPolicy policy) const {
if ((formats_ & OSExchangeData::URL) == 0) {
if (std::optional<GURL> plaintext_url = GetPlainTextURL();
plaintext_url.has_value()) {
DCHECK(plaintext_url->is_valid());
return UrlInfo{std::move(plaintext_url).value(), std::u16string()};
} else if (GURL url; policy == FilenameToURLPolicy::CONVERT_FILENAMES &&
GetFileURL(&url)) {
DCHECK(url.is_valid());
return UrlInfo{std::move(url), std::u16string()};
}
return std::nullopt;
}
if (!url_.is_valid()) {
return std::nullopt;
}
return UrlInfo{url_, title_};
}
std::optional<std::vector<GURL>> OSExchangeDataProviderNonBacked::GetURLs(
FilenameToURLPolicy policy) const {
std::vector<GURL> local_urls;
if (std::optional<UrlInfo> url_info =
GetURLAndTitle(FilenameToURLPolicy::DO_NOT_CONVERT_FILENAMES);
url_info.has_value()) {
local_urls.push_back(url_info->url);
}
if (policy == FilenameToURLPolicy::CONVERT_FILENAMES) {
if (std::optional<std::vector<FileInfo>> fileinfos = GetFilenames();
fileinfos.has_value()) {
for (const auto& fileinfo : fileinfos.value()) {
local_urls.push_back(net::FilePathToFileURL(fileinfo.path));
}
}
}
if (local_urls.size()) {
return local_urls;
}
return std::nullopt;
}
std::optional<std::vector<FileInfo>>
OSExchangeDataProviderNonBacked::GetFilenames() const {
if ((formats_ & OSExchangeData::FILE_NAME) == 0)
return std::nullopt;
return filenames_;
}
std::optional<base::Pickle> OSExchangeDataProviderNonBacked::GetPickledData(
const ClipboardFormatType& format) const {
const auto i = pickle_data_.find(format);
if (i == pickle_data_.end()) {
return std::nullopt;
}
return i->second;
}
bool OSExchangeDataProviderNonBacked::HasString() const {
return (formats_ & OSExchangeData::STRING) != 0;
}
bool OSExchangeDataProviderNonBacked::HasURL(FilenameToURLPolicy policy) const {
if ((formats_ & OSExchangeData::URL) != 0) {
return true;
}
// No URL, see if we have plain text that can be parsed as a URL.
return GetPlainTextURL().has_value() ||
(policy == FilenameToURLPolicy::CONVERT_FILENAMES &&
GetFileURL(nullptr));
}
bool OSExchangeDataProviderNonBacked::HasFile() const {
return (formats_ & OSExchangeData::FILE_NAME) != 0;
}
bool OSExchangeDataProviderNonBacked::HasCustomFormat(
const ClipboardFormatType& format) const {
return base::Contains(pickle_data_, format);
}
void OSExchangeDataProviderNonBacked::SetFileContents(
const base::FilePath& filename,
const std::string& file_contents) {
file_contents_filename_ = filename;
file_contents_ = file_contents;
}
std::optional<OSExchangeDataProvider::FileContentsInfo>
OSExchangeDataProviderNonBacked::GetFileContents() const {
if (file_contents_filename_.empty()) {
return std::nullopt;
}
return FileContentsInfo{.filename = file_contents_filename_,
.file_contents = file_contents_};
}
bool OSExchangeDataProviderNonBacked::HasFileContents() const {
return !file_contents_filename_.empty();
}
void OSExchangeDataProviderNonBacked::SetHtml(const std::u16string& html,
const GURL& base_url) {
formats_ |= OSExchangeData::HTML;
html_ = html;
base_url_ = base_url;
}
std::optional<OSExchangeData::HtmlInfo>
OSExchangeDataProviderNonBacked::GetHtml() const {
if (!HasHtml()) {
return std::nullopt;
}
return HtmlInfo{
.html = html_,
.base_url = base_url_,
};
}
bool OSExchangeDataProviderNonBacked::HasHtml() const {
return ((formats_ & OSExchangeData::HTML) != 0);
}
void OSExchangeDataProviderNonBacked::SetDragImage(
const gfx::ImageSkia& image,
const gfx::Vector2d& cursor_offset) {
drag_image_ = image;
drag_image_offset_ = cursor_offset;
}
gfx::ImageSkia OSExchangeDataProviderNonBacked::GetDragImage() const {
return drag_image_;
}
gfx::Vector2d OSExchangeDataProviderNonBacked::GetDragImageOffset() const {
return drag_image_offset_;
}
bool OSExchangeDataProviderNonBacked::GetFileURL(GURL* url) const {
if (!HasFile()) {
return false;
}
base::FilePath file_path = filenames_[0].path;
GURL test_url = net::FilePathToFileURL(file_path);
if (!test_url.is_valid()) {
return false;
}
if (url) {
*url = std::move(test_url);
}
return true;
}
std::optional<GURL> OSExchangeDataProviderNonBacked::GetPlainTextURL() const {
if ((formats_ & OSExchangeData::STRING) == 0)
return std::nullopt;
GURL test_url(string_);
if (!test_url.is_valid()) {
return std::nullopt;
}
if (base::FeatureList::IsEnabled(
features::kDragDropOnlySynthesizeHttpOrHttpsUrlsFromText) &&
IsRendererTainted() && !test_url.SchemeIsHTTPOrHTTPS()) {
return std::nullopt;
}
return test_url;
}
void OSExchangeDataProviderNonBacked::SetSource(
std::unique_ptr<DataTransferEndpoint> data_source) {
source_ = std::move(data_source);
}
DataTransferEndpoint* OSExchangeDataProviderNonBacked::GetSource() const {
return source_.get();
}
void OSExchangeDataProviderNonBacked::CopyData(
OSExchangeDataProviderNonBacked* provider) const {
DCHECK(provider);
provider->formats_ = formats_;
provider->string_ = string_;
provider->url_ = url_;
provider->title_ = title_;
provider->filenames_ = filenames_;
provider->pickle_data_ = pickle_data_;
provider->file_contents_filename_ = file_contents_filename_;
provider->file_contents_ = file_contents_;
provider->html_ = html_;
provider->base_url_ = base_url_;
provider->source_ =
source_ ? std::make_unique<DataTransferEndpoint>(*source_.get())
: nullptr;
provider->tainted_by_renderer_origin_ = tainted_by_renderer_origin_;
provider->is_from_privileged_ = is_from_privileged_;
}
} // namespace ui