blob: 13fca50d4359405eb3cde99eb9b0b67a540364ab [file] [log] [blame]
// Copyright 2017 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 "components/exo/data_offer.h"
#include "base/files/file_util.h"
#include "base/memory/ref_counted_memory.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task_scheduler/post_task.h"
#include "components/exo/data_offer_delegate.h"
#include "components/exo/data_offer_observer.h"
#include "components/exo/file_helper.h"
#include "ui/base/clipboard/clipboard.h"
#include "ui/base/dragdrop/file_info.h"
#include "ui/base/dragdrop/os_exchange_data.h"
#include "url/gurl.h"
namespace exo {
namespace {
constexpr char kTextMimeTypeUtf8[] = "text/plain;charset=utf-8";
constexpr char kUriListSeparator[] = "\r\n";
class RefCountedString16 : public base::RefCountedMemory {
public:
static scoped_refptr<RefCountedString16> TakeString(
base::string16&& to_destroy) {
scoped_refptr<RefCountedString16> self(new RefCountedString16);
to_destroy.swap(self->data_);
return self;
}
// Overridden from base::RefCountedMemory:
const unsigned char* front() const override {
return reinterpret_cast<const unsigned char*>(data_.data());
}
size_t size() const override { return data_.size() * sizeof(base::char16); }
protected:
~RefCountedString16() override {}
private:
base::string16 data_;
};
void WriteFileDescriptor(base::ScopedFD fd,
scoped_refptr<base::RefCountedMemory> memory) {
if (!base::WriteFileDescriptor(fd.get(),
reinterpret_cast<const char*>(memory->front()),
memory->size()))
DLOG(ERROR) << "Failed to write drop data";
}
} // namespace
DataOffer::DataOffer(DataOfferDelegate* delegate) : delegate_(delegate) {}
DataOffer::~DataOffer() {
delegate_->OnDataOfferDestroying(this);
for (DataOfferObserver& observer : observers_) {
observer.OnDataOfferDestroying(this);
}
}
void DataOffer::AddObserver(DataOfferObserver* observer) {
observers_.AddObserver(observer);
}
void DataOffer::RemoveObserver(DataOfferObserver* observer) {
observers_.RemoveObserver(observer);
}
void DataOffer::Accept(const std::string& mime_type) {}
void DataOffer::Receive(const std::string& mime_type, base::ScopedFD fd) {
const auto it = data_.find(mime_type);
if (it == data_.end()) {
DLOG(ERROR) << "Unexpected mime type is requested";
return;
}
base::PostTaskWithTraits(
FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_BLOCKING},
base::BindOnce(&WriteFileDescriptor, std::move(fd), it->second));
}
void DataOffer::Finish() {}
void DataOffer::SetActions(const base::flat_set<DndAction>& dnd_actions,
DndAction preferred_action) {
dnd_action_ = preferred_action;
delegate_->OnAction(preferred_action);
}
void DataOffer::SetSourceActions(
const base::flat_set<DndAction>& source_actions) {
source_actions_ = source_actions;
delegate_->OnSourceActions(source_actions);
}
void DataOffer::SetDropData(FileHelper* file_helper,
const ui::OSExchangeData& data) {
DCHECK_EQ(0u, data_.size());
if (data.HasString()) {
base::string16 string_content;
if (data.GetString(&string_content)) {
data_.emplace(std::string(ui::Clipboard::kMimeTypeText),
RefCountedString16::TakeString(std::move(string_content)));
}
}
if (data.HasFile()) {
std::vector<ui::FileInfo> files;
if (data.GetFilenames(&files)) {
base::string16 url_list;
for (const auto& info : files) {
GURL url;
// TODO(hirono): Need to fill the corret app_id.
if (file_helper->GetUrlFromPath(/* app_id */ "", info.path, &url)) {
if (!url_list.empty())
url_list += base::UTF8ToUTF16(kUriListSeparator);
url_list += base::UTF8ToUTF16(url.spec());
}
}
data_.emplace(file_helper->GetMimeTypeForUriList(),
RefCountedString16::TakeString(std::move(url_list)));
}
}
for (const auto& pair : data_) {
delegate_->OnOffer(pair.first);
}
}
void DataOffer::SetClipboardData(FileHelper* file_helper,
const ui::Clipboard& data) {
DCHECK_EQ(0u, data_.size());
if (data.IsFormatAvailable(ui::Clipboard::GetPlainTextWFormatType(),
ui::CLIPBOARD_TYPE_COPY_PASTE)) {
base::string16 content;
data.ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE, &content);
std::string utf8_content = base::UTF16ToUTF8(content);
data_.emplace(std::string(kTextMimeTypeUtf8),
base::RefCountedString::TakeString(&utf8_content));
}
for (const auto& pair : data_) {
delegate_->OnOffer(pair.first);
}
}
} // namespace exo