Commit 300a38d4 authored by Alexander Dunaev's avatar Alexander Dunaev Committed by Commit Bot

[ozone/wayland] Added support for more MIME types in drag'n'drop.

The current drag'n'drop implementation only supports transfer of text.

This CL adds support for additional types such as files, URLs, and HTML.

R=msisov@igalia.com

Bug: 1004715
Change-Id: Ic7430c0bf7820c55b8ac99b01a3f684c2d7c8a51
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1815863
Commit-Queue: Alexander Dunaev <adunaev@igalia.com>
Reviewed-by: default avatarSadrul Chowdhury <sadrul@chromium.org>
Reviewed-by: default avatarMaksim Sisov <msisov@igalia.com>
Cr-Commit-Position: refs/heads/master@{#701932}
parent 270322a2
...@@ -292,6 +292,7 @@ source_set("wayland_unittests") { ...@@ -292,6 +292,7 @@ source_set("wayland_unittests") {
"//ui/ozone:test_support", "//ui/ozone:test_support",
"//ui/ozone/common/linux:drm", "//ui/ozone/common/linux:drm",
"//ui/ozone/common/linux:gbm", "//ui/ozone/common/linux:gbm",
"//ui/platform_window/platform_window_handler",
] ]
import("//ui/base/ui_features.gni") import("//ui/base/ui_features.gni")
......
...@@ -5,6 +5,7 @@ include_rules = [ ...@@ -5,6 +5,7 @@ include_rules = [
"+mojo/public", "+mojo/public",
"+ui/base/clipboard/clipboard_constants.h", "+ui/base/clipboard/clipboard_constants.h",
"+ui/base/dragdrop/drag_drop_types.h", "+ui/base/dragdrop/drag_drop_types.h",
"+ui/base/dragdrop/file_info.h",
"+ui/base/dragdrop/os_exchange_data.h", "+ui/base/dragdrop/os_exchange_data.h",
"+ui/base/dragdrop/os_exchange_data_provider_aura.h", "+ui/base/dragdrop/os_exchange_data_provider_aura.h",
] ]
...@@ -131,12 +131,12 @@ bool DrawBitmap(const SkBitmap& bitmap, ui::WaylandShmBuffer* out_buffer) { ...@@ -131,12 +131,12 @@ bool DrawBitmap(const SkBitmap& bitmap, ui::WaylandShmBuffer* out_buffer) {
return true; return true;
} }
void ReadDataFromFD(base::ScopedFD fd, std::string* contents) { void ReadDataFromFD(base::ScopedFD fd, std::vector<uint8_t>* contents) {
DCHECK(contents); DCHECK(contents);
char buffer[1 << 10]; // 1 kB in bytes. uint8_t buffer[1 << 10]; // 1 kB in bytes.
ssize_t length; ssize_t length;
while ((length = read(fd.get(), buffer, sizeof(buffer))) > 0) while ((length = read(fd.get(), buffer, sizeof(buffer))) > 0)
contents->append(buffer, length); contents->insert(contents->end(), buffer, buffer + length);
} }
} // namespace wl } // namespace wl
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
#ifndef UI_OZONE_PLATFORM_WAYLAND_COMMON_WAYLAND_UTIL_H_ #ifndef UI_OZONE_PLATFORM_WAYLAND_COMMON_WAYLAND_UTIL_H_
#define UI_OZONE_PLATFORM_WAYLAND_COMMON_WAYLAND_UTIL_H_ #define UI_OZONE_PLATFORM_WAYLAND_COMMON_WAYLAND_UTIL_H_
#include <string> #include <vector>
#include <wayland-client.h> #include <wayland-client.h>
...@@ -43,7 +43,7 @@ uint32_t IdentifyDirection(const ui::WaylandConnection& connection, ...@@ -43,7 +43,7 @@ uint32_t IdentifyDirection(const ui::WaylandConnection& connection,
bool DrawBitmap(const SkBitmap& bitmap, ui::WaylandShmBuffer* out_buffer); bool DrawBitmap(const SkBitmap& bitmap, ui::WaylandShmBuffer* out_buffer);
// Helper function to read data from a file. // Helper function to read data from a file.
void ReadDataFromFD(base::ScopedFD fd, std::string* contents); void ReadDataFromFD(base::ScopedFD fd, std::vector<uint8_t>* contents);
} // namespace wl } // namespace wl
......
...@@ -53,7 +53,7 @@ void GtkPrimarySelectionDevice::OnSelection( ...@@ -53,7 +53,7 @@ void GtkPrimarySelectionDevice::OnSelection(
self->ResetDataOffer(); self->ResetDataOffer();
// Clear Clipboard cache. // Clear Clipboard cache.
self->connection()->clipboard()->SetData(std::string(), std::string()); self->connection()->clipboard()->SetData({}, {});
return; return;
} }
......
...@@ -54,7 +54,7 @@ void WaylandDataDeviceBase::ResetDataOffer() { ...@@ -54,7 +54,7 @@ void WaylandDataDeviceBase::ResetDataOffer() {
void WaylandDataDeviceBase::ReadClipboardDataFromFD( void WaylandDataDeviceBase::ReadClipboardDataFromFD(
base::ScopedFD fd, base::ScopedFD fd,
const std::string& mime_type) { const std::string& mime_type) {
std::string contents; std::vector<uint8_t> contents;
wl::ReadDataFromFD(std::move(fd), &contents); wl::ReadDataFromFD(std::move(fd), &contents);
connection_->clipboard()->SetData(contents, mime_type); connection_->clipboard()->SetData(contents, mime_type);
} }
...@@ -89,8 +89,14 @@ void WaylandDataDeviceBase::DeferredReadCallback(void* data, ...@@ -89,8 +89,14 @@ void WaylandDataDeviceBase::DeferredReadCallback(void* data,
void WaylandDataDeviceBase::DeferredReadCallbackInternal(struct wl_callback* cb, void WaylandDataDeviceBase::DeferredReadCallbackInternal(struct wl_callback* cb,
uint32_t time) { uint32_t time) {
DCHECK(!deferred_read_closure_.is_null()); DCHECK(!deferred_read_closure_.is_null());
std::move(deferred_read_closure_).Run();
// The callback must be reset before invoking the closure because the latter
// may want to set another callback. That typically happens when non-trivial
// data types are dropped; they have fallbacks to plain text so several
// roundtrips to data are chained.
deferred_read_callback_.reset(); deferred_read_callback_.reset();
std::move(deferred_read_closure_).Run();
} }
} // namespace internal } // namespace internal
......
...@@ -58,8 +58,7 @@ class WaylandDataDeviceBase { ...@@ -58,8 +58,7 @@ class WaylandDataDeviceBase {
struct wl_callback* cb, struct wl_callback* cb,
uint32_t time); uint32_t time);
void DeferredReadCallbackInternal(struct wl_callback* cb, void DeferredReadCallbackInternal(struct wl_callback* cb, uint32_t time);
uint32_t time);
// Used to call out to WaylandConnection once clipboard data // Used to call out to WaylandConnection once clipboard data
// has been successfully read. // has been successfully read.
......
...@@ -108,13 +108,12 @@ void WaylandClipboard::DataSourceCancelled(ClipboardBuffer buffer) { ...@@ -108,13 +108,12 @@ void WaylandClipboard::DataSourceCancelled(ClipboardBuffer buffer) {
} }
} }
void WaylandClipboard::SetData(const std::string& contents, void WaylandClipboard::SetData(const std::vector<uint8_t>& contents,
const std::string& mime_type) { const std::string& mime_type) {
if (!data_map_) if (!data_map_)
return; return;
(*data_map_)[mime_type] = (*data_map_)[mime_type] = contents;
std::vector<uint8_t>(contents.begin(), contents.end());
if (!read_clipboard_closure_.is_null()) { if (!read_clipboard_closure_.is_null()) {
auto it = data_map_->find(mime_type); auto it = data_map_->find(mime_type);
......
...@@ -5,6 +5,9 @@ ...@@ -5,6 +5,9 @@
#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_CLIPBOARD_H_ #ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_CLIPBOARD_H_
#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_CLIPBOARD_H_ #define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_CLIPBOARD_H_
#include <string>
#include <vector>
#include "base/callback.h" #include "base/callback.h"
#include "base/macros.h" #include "base/macros.h"
#include "ui/ozone/platform/wayland/host/wayland_data_source.h" #include "ui/ozone/platform/wayland/host/wayland_data_source.h"
...@@ -49,7 +52,8 @@ class WaylandClipboard : public PlatformClipboard { ...@@ -49,7 +52,8 @@ class WaylandClipboard : public PlatformClipboard {
PlatformClipboard::SequenceNumberUpdateCb cb) override; PlatformClipboard::SequenceNumberUpdateCb cb) override;
void DataSourceCancelled(ClipboardBuffer buffer); void DataSourceCancelled(ClipboardBuffer buffer);
void SetData(const std::string& contents, const std::string& mime_type); void SetData(const std::vector<uint8_t>& contents,
const std::string& mime_type);
void UpdateSequenceNumber(ClipboardBuffer buffer); void UpdateSequenceNumber(ClipboardBuffer buffer);
private: private:
......
...@@ -169,7 +169,7 @@ void WaylandConnection::DeliverDragData(const std::string& mime_type, ...@@ -169,7 +169,7 @@ void WaylandConnection::DeliverDragData(const std::string& mime_type,
void WaylandConnection::RequestDragData( void WaylandConnection::RequestDragData(
const std::string& mime_type, const std::string& mime_type,
base::OnceCallback<void(const std::string&)> callback) { base::OnceCallback<void(const std::vector<uint8_t>&)> callback) {
data_device_->RequestDragData(mime_type, std::move(callback)); data_device_->RequestDragData(mime_type, std::move(callback));
} }
......
...@@ -119,8 +119,9 @@ class WaylandConnection : public PlatformEventSource, ...@@ -119,8 +119,9 @@ class WaylandConnection : public PlatformEventSource,
// Requests the data to the platform when Chromium gets drag-and-drop started // Requests the data to the platform when Chromium gets drag-and-drop started
// by others. Once reading the data from platform is done, |callback| should // by others. Once reading the data from platform is done, |callback| should
// be called with the data. // be called with the data.
void RequestDragData(const std::string& mime_type, void RequestDragData(
base::OnceCallback<void(const std::string&)> callback); const std::string& mime_type,
base::OnceCallback<void(const std::vector<uint8_t>&)> callback);
// Returns true when dragging is entered or started. // Returns true when dragging is entered or started.
bool IsDragInProgress(); bool IsDragInProgress();
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include "ui/ozone/platform/wayland/host/internal/wayland_data_device_base.h" #include "ui/ozone/platform/wayland/host/internal/wayland_data_device_base.h"
#include "ui/ozone/platform/wayland/host/wayland_data_offer.h" #include "ui/ozone/platform/wayland/host/wayland_data_offer.h"
#include "ui/ozone/platform/wayland/host/wayland_shm_buffer.h" #include "ui/ozone/platform/wayland/host/wayland_shm_buffer.h"
#include "ui/ozone/public/platform_clipboard.h"
class SkBitmap; class SkBitmap;
...@@ -40,8 +41,9 @@ class WaylandDataDevice : public internal::WaylandDataDeviceBase { ...@@ -40,8 +41,9 @@ class WaylandDataDevice : public internal::WaylandDataDeviceBase {
// Requests the data to the platform when Chromium gets drag-and-drop started // Requests the data to the platform when Chromium gets drag-and-drop started
// by others. Once reading the data from platform is done, |callback| should // by others. Once reading the data from platform is done, |callback| should
// be called with the data. // be called with the data.
void RequestDragData(const std::string& mime_type, void RequestDragData(
base::OnceCallback<void(const std::string&)> callback); const std::string& mime_type,
base::OnceCallback<void(const PlatformClipboard::Data&)> callback);
// Delivers the data owned by Chromium which initiates drag-and-drop. |buffer| // Delivers the data owned by Chromium which initiates drag-and-drop. |buffer|
// is an output parameter and it should be filled with the data corresponding // is an output parameter and it should be filled with the data corresponding
// to mime_type. // to mime_type.
...@@ -59,7 +61,7 @@ class WaylandDataDevice : public internal::WaylandDataDeviceBase { ...@@ -59,7 +61,7 @@ class WaylandDataDevice : public internal::WaylandDataDeviceBase {
private: private:
void ReadDragDataFromFD( void ReadDragDataFromFD(
base::ScopedFD fd, base::ScopedFD fd,
base::OnceCallback<void(const std::string&)> callback); base::OnceCallback<void(const PlatformClipboard::Data&)> callback);
// If source_data_ is not set, data is being dragged from an external // If source_data_ is not set, data is being dragged from an external
// application (non-chromium). // application (non-chromium).
...@@ -105,7 +107,7 @@ class WaylandDataDevice : public internal::WaylandDataDeviceBase { ...@@ -105,7 +107,7 @@ class WaylandDataDevice : public internal::WaylandDataDeviceBase {
const SkBitmap* PrepareDragIcon(const OSExchangeData& data); const SkBitmap* PrepareDragIcon(const OSExchangeData& data);
void DrawDragIcon(const SkBitmap* bitmap); void DrawDragIcon(const SkBitmap* bitmap);
void OnDragDataReceived(const std::string& contents); void OnDragDataReceived(const PlatformClipboard::Data& contents);
// HandleUnprocessedMimeTypes asynchronously request and read data for every // HandleUnprocessedMimeTypes asynchronously request and read data for every
// negotiated mime type, one after another (OnDragDataReceived calls back // negotiated mime type, one after another (OnDragDataReceived calls back
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "base/files/file_util.h" #include "base/files/file_util.h"
#include "ui/base/clipboard/clipboard_constants.h" #include "ui/base/clipboard/clipboard_constants.h"
#include "ui/base/dragdrop/drag_drop_types.h" #include "ui/base/dragdrop/drag_drop_types.h"
#include "ui/base/dragdrop/os_exchange_data.h"
#include "ui/ozone/platform/wayland/host/wayland_connection.h" #include "ui/ozone/platform/wayland/host/wayland_connection.h"
#include "ui/ozone/platform/wayland/host/wayland_window.h" #include "ui/ozone/platform/wayland/host/wayland_window.h"
...@@ -38,10 +39,24 @@ void WaylandDataSource::WriteToClipboard( ...@@ -38,10 +39,24 @@ void WaylandDataSource::WriteToClipboard(
} }
void WaylandDataSource::Offer(const ui::OSExchangeData& data) { void WaylandDataSource::Offer(const ui::OSExchangeData& data) {
// TODO(jkim): Handle mime types based on data. // Drag'n'drop manuals usually suggest putting data in order so the more
// specific a MIME type is, the earlier it occurs in the list. Wayland specs
// don't say anything like that, but here we follow that common practice:
// begin with URIs and end with plain text. Just in case.
std::vector<std::string> mime_types; std::vector<std::string> mime_types;
mime_types.push_back(kMimeTypeText); if (data.HasFile()) {
mime_types.push_back(kMimeTypeTextUtf8); mime_types.push_back(kMimeTypeURIList);
}
if (data.HasURL(ui::OSExchangeData::FilenameToURLPolicy::CONVERT_FILENAMES)) {
mime_types.push_back(kMimeTypeMozillaURL);
}
if (data.HasHtml()) {
mime_types.push_back(kMimeTypeHTML);
}
if (data.HasString()) {
mime_types.push_back(kMimeTypeTextUtf8);
mime_types.push_back(kMimeTypeText);
}
source_window_ = source_window_ =
connection_->wayland_window_manager()->GetCurrentFocusedWindow(); connection_->wayland_window_manager()->GetCurrentFocusedWindow();
......
...@@ -19,9 +19,12 @@ namespace wl { ...@@ -19,9 +19,12 @@ namespace wl {
namespace { namespace {
void WriteDataOnWorkerThread(base::ScopedFD fd, const std::string& utf8_text) { void WriteDataOnWorkerThread(base::ScopedFD fd,
if (!base::WriteFileDescriptor(fd.get(), utf8_text.data(), utf8_text.size())) const ui::PlatformClipboard::Data& data) {
if (!base::WriteFileDescriptor(
fd.get(), reinterpret_cast<const char*>(data.data()), data.size())) {
LOG(ERROR) << "Failed to write selection data to clipboard."; LOG(ERROR) << "Failed to write selection data to clipboard.";
}
} }
void DataOfferAccept(wl_client* client, void DataOfferAccept(wl_client* client,
...@@ -70,17 +73,15 @@ TestDataOffer::~TestDataOffer() {} ...@@ -70,17 +73,15 @@ TestDataOffer::~TestDataOffer() {}
void TestDataOffer::Receive(const std::string& mime_type, base::ScopedFD fd) { void TestDataOffer::Receive(const std::string& mime_type, base::ScopedFD fd) {
DCHECK(fd.is_valid()); DCHECK(fd.is_valid());
std::string text_data;
if (mime_type == kTextMimeTypeUtf8) task_runner_->PostTask(FROM_HERE,
text_data = kSampleClipboardText; base::BindOnce(&WriteDataOnWorkerThread, std::move(fd),
else if (mime_type == kTextMimeTypeText) data_to_offer_[mime_type]));
text_data = kSampleTextForDragAndDrop;
task_runner_->PostTask(FROM_HERE, base::BindOnce(&WriteDataOnWorkerThread,
std::move(fd), text_data));
} }
void TestDataOffer::OnOffer(const std::string& mime_type) { void TestDataOffer::OnOffer(const std::string& mime_type,
const ui::PlatformClipboard::Data& data) {
data_to_offer_[mime_type] = data;
wl_data_offer_send_offer(resource(), mime_type.c_str()); wl_data_offer_send_offer(resource(), mime_type.c_str());
} }
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/threading/thread.h" #include "base/threading/thread.h"
#include "ui/ozone/platform/wayland/test/server_object.h" #include "ui/ozone/platform/wayland/test/server_object.h"
#include "ui/ozone/public/platform_clipboard.h"
struct wl_resource; struct wl_resource;
...@@ -32,10 +33,13 @@ class TestDataOffer : public ServerObject { ...@@ -32,10 +33,13 @@ class TestDataOffer : public ServerObject {
~TestDataOffer() override; ~TestDataOffer() override;
void Receive(const std::string& mime_type, base::ScopedFD fd); void Receive(const std::string& mime_type, base::ScopedFD fd);
void OnOffer(const std::string& mime_type); void OnOffer(const std::string& mime_type,
const ui::PlatformClipboard::Data& data);
private: private:
const scoped_refptr<base::SequencedTaskRunner> task_runner_; const scoped_refptr<base::SequencedTaskRunner> task_runner_;
ui::PlatformClipboard::DataMap data_to_offer_;
base::WeakPtrFactory<TestDataOffer> write_data_weak_ptr_factory_; base::WeakPtrFactory<TestDataOffer> write_data_weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(TestDataOffer); DISALLOW_COPY_AND_ASSIGN(TestDataOffer);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment