From 6fdd02394e1067a75f80b7ebee7458cd6d8e6282 Mon Sep 17 00:00:00 2001 From: Antonio Gomes Date: Fri, 24 Sep 2021 03:20:54 +0000 Subject: [PATCH] [exo] Add initial support to 'chromium/x-web-custom-data' mime type This CL adds a initial support in Exo to chromium's custom data mime types. Particularly, it also adds support to Ozone/Wayland (ie Lacros) to make use of this support, and offer them, upon request. This CL is the basis for supporting "WebUI Tab Dragging" with both touch and mouse to trigger work ChromeOS. BUG=1236708 Change-Id: Ibf000ae32915f75b9bb959e49e70e4c480317c85 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3166178 Auto-Submit: Antonio Gomes Reviewed-by: Mitsuru Oshima Reviewed-by: Nick Yamane Commit-Queue: Antonio Gomes Cr-Commit-Position: refs/heads/main@{#924624} --- components/exo/data_source.cc | 7 ++++ components/exo/data_source.h | 13 +++--- components/exo/data_source_unittest.cc | 42 +++++++++++++++---- components/exo/drag_drop_operation.cc | 14 +++++++ components/exo/drag_drop_operation.h | 2 + components/exo/seat.cc | 15 ++++++- components/exo/seat.h | 5 +++ .../host/wayland_data_drag_controller.cc | 2 +- .../host/wayland_exchange_data_provider.cc | 10 +++++ 9 files changed, 94 insertions(+), 16 deletions(-) diff --git a/components/exo/data_source.cc b/components/exo/data_source.cc index 6832f42b8ffa49..4359ebf2699378 100644 --- a/components/exo/data_source.cc +++ b/components/exo/data_source.cc @@ -34,6 +34,7 @@ constexpr char kTextRTF[] = "text/rtf"; constexpr char kTextHTML[] = "text/html"; constexpr char kTextUriList[] = "text/uri-list"; constexpr char kApplicationOctetStream[] = "application/octet-stream"; +constexpr char kWebCustomData[] = "chromium/x-web-custom-data"; constexpr char kUtfPrefix[] = "UTF"; constexpr char kEncoding16[] = "16"; @@ -259,6 +260,7 @@ void DataSource::GetDataForPreferredMimeTypes( ReadDataCallback image_reader, ReadDataCallback filenames_reader, ReadFileContentsDataCallback file_contents_reader, + ReadDataCallback web_custom_data_reader, base::RepeatingClosure failure_callback) { std::string text_mime; std::string rtf_mime; @@ -266,6 +268,7 @@ void DataSource::GetDataForPreferredMimeTypes( std::string image_mime; std::string filenames_mime; std::string file_contents_mime; + std::string web_custom_data_mime; int text_rank = std::numeric_limits::max(); int html_rank = std::numeric_limits::max(); @@ -317,6 +320,8 @@ void DataSource::GetDataForPreferredMimeTypes( filenames_mime = mime_type; } else if (!GetApplicationOctetStreamName(mime_type).empty()) { file_contents_mime = mime_type; + } else if (net::MatchesMimeType(std::string(kWebCustomData), mime_type)) { + web_custom_data_mime = mime_type; } } @@ -338,6 +343,8 @@ void DataSource::GetDataForPreferredMimeTypes( read_data_weak_ptr_factory_.GetWeakPtr(), std::move(file_contents_reader)), failure_callback); + ReadData(web_custom_data_mime, std::move(web_custom_data_reader), + failure_callback); } void DataSource::OnTextRead(ReadTextDataCallback callback, diff --git a/components/exo/data_source.h b/components/exo/data_source.h index 394f37bfa78a9f..2618ea49134d23 100644 --- a/components/exo/data_source.h +++ b/components/exo/data_source.h @@ -25,8 +25,8 @@ class DataSource { public: // The maximum number of different data types that will be read by // GetDataForPreferredMimeTypes (plain text, RTF, HTML, image, text/uri-list, - // application/octet-stream). - static constexpr int kMaxDataTypes = 6; + // application/octet-stream, chromium/x-web-custom-data). + static constexpr int kMaxDataTypes = 7; explicit DataSource(DataSourceDelegate* delegate); @@ -71,12 +71,12 @@ class DataSource { // Search the set of offered MIME types for the most preferred of each of the // following categories: text/plain*, text/rtf, text/html*, image/*, - // text/uri-list. If any usable MIME types in a given category are available, - // the corresponding + // text/uri-list, chromium/x-web-custom-data. If any usable MIME types in a + // given category are available, the corresponding // |*_reader| input callback will be called with the best one and the // corresponding data. For any category that has no available MIME types, // |failure_callback| is run. |failure_callback| may therefore be run as many - // as four times. + // as seven times. using ReadDataCallback = base::OnceCallback&)>; using ReadTextDataCallback = @@ -85,6 +85,8 @@ class DataSource { base::OnceCallback&)>; + using ReadWebCustomDataCallback = + base::OnceCallback&)>; void GetDataForPreferredMimeTypes( ReadTextDataCallback text_reader, ReadDataCallback rtf_reader, @@ -92,6 +94,7 @@ class DataSource { ReadDataCallback image_reader, ReadDataCallback filenames_reader, ReadFileContentsDataCallback file_contents_reader, + ReadDataCallback web_custom_data_reader, base::RepeatingClosure failure_callback); void ReadDataForTesting(const std::string& mime_type, diff --git a/components/exo/data_source_unittest.cc b/components/exo/data_source_unittest.cc index 0039d46f72babd..69a383ac4487c8 100644 --- a/components/exo/data_source_unittest.cc +++ b/components/exo/data_source_unittest.cc @@ -81,19 +81,30 @@ void CheckFileContentsMimeType(const FileContents& file_contents, std::move(counter).Run(); } +void CheckWebCustomDataMimeType(const std::string& expected, + base::OnceClosure counter, + const std::string& mime_type, + const std::vector& data) { + EXPECT_FALSE(mime_type.empty()); + EXPECT_EQ(expected, mime_type); + std::move(counter).Run(); +} + void IncrementFailureCounter(std::atomic_int* failure_count, base::RepeatingClosure counter) { ++(*failure_count); std::move(counter).Run(); } -void CheckMimeTypesReceived(DataSource* data_source, - const std::string& text_mime, - const std::string& rtf_mime, - const std::string& html_mime, - const std::string& image_mime, - const std::string& filenames_mime, - const FileContents& file_contents) { +void CheckMimeTypesReceived( + DataSource* data_source, + const std::string& text_mime, + const std::string& rtf_mime, + const std::string& html_mime, + const std::string& image_mime, + const std::string& filenames_mime, + const FileContents& file_contents, + const std::string& web_custom_data_mime = std::string()) { base::RunLoop run_loop; base::RepeatingClosure counter = base::BarrierClosure(DataSource::kMaxDataTypes, run_loop.QuitClosure()); @@ -106,12 +117,15 @@ void CheckMimeTypesReceived(DataSource* data_source, base::BindOnce(&CheckMimeType, image_mime, counter), base::BindOnce(&CheckMimeType, filenames_mime, counter), base::BindOnce(&CheckFileContentsMimeType, file_contents, counter), + base::BindOnce(&CheckWebCustomDataMimeType, web_custom_data_mime, + counter), base::BindRepeating(&IncrementFailureCounter, &failure_count, counter)); run_loop.Run(); int expected_failure_count = 0; - for (const auto& mime_type : {text_mime, rtf_mime, html_mime, image_mime, - filenames_mime, file_contents.mime_type}) { + for (const auto& mime_type : + {text_mime, rtf_mime, html_mime, image_mime, filenames_mime, + file_contents.mime_type, web_custom_data_mime}) { if (mime_type.empty()) ++expected_failure_count; } @@ -339,5 +353,15 @@ TEST_F(DataSourceTest, OctetStreamWithQuotedName) { {"application/octet-stream;name=\"t\\\\est\\\".jpg\"", "t\\est\".jpg"}); } +TEST_F(DataSourceTest, WebCustomDataMime) { + TestDataSourceDelegate delegate; + DataSource data_source(&delegate); + std::string web_custom_data_mime("chromium/x-web-custom-data"); + data_source.Offer(web_custom_data_mime); + + CheckMimeTypesReceived(&data_source, "", "", "", "", "", {}, + web_custom_data_mime); +} + } // namespace } // namespace exo diff --git a/components/exo/drag_drop_operation.cc b/components/exo/drag_drop_operation.cc index 97cb9d6caed1e6..b4f9f5a71f6383 100644 --- a/components/exo/drag_drop_operation.cc +++ b/components/exo/drag_drop_operation.cc @@ -6,6 +6,7 @@ #include "base/barrier_closure.h" #include "base/check.h" +#include "base/pickle.h" #include "base/strings/string_split.h" #include "base/threading/sequenced_task_runner_handle.h" #include "build/chromeos_buildflags.h" @@ -226,6 +227,8 @@ DragDropOperation::DragDropOperation( origin->window()), base::BindOnce(&DragDropOperation::OnFileContentsRead, weak_ptr_factory_.GetWeakPtr()), + base::BindOnce(&DragDropOperation::OnWebCustomDataRead, + weak_ptr_factory_.GetWeakPtr()), counter_); } @@ -290,6 +293,17 @@ void DragDropOperation::OnFileContentsRead(const std::string& mime_type, counter_.Run(); } +void DragDropOperation::OnWebCustomDataRead(const std::string& mime_type, + const std::vector& data) { + DCHECK(os_exchange_data_); + base::Pickle pickle(reinterpret_cast(data.data()), data.size()); + os_exchange_data_->SetPickledData( + ui::ClipboardFormatType::WebCustomDataType(), pickle); + + mime_type_ = mime_type; + counter_.Run(); +} + void DragDropOperation::OnDragIconCaptured(const SkBitmap& icon_bitmap) { DCHECK(icon_); diff --git a/components/exo/drag_drop_operation.h b/components/exo/drag_drop_operation.h index ffcf85f8c602cf..35058f7d6510cb 100644 --- a/components/exo/drag_drop_operation.h +++ b/components/exo/drag_drop_operation.h @@ -108,6 +108,8 @@ class DragDropOperation : public DataSourceObserver, void OnFileContentsRead(const std::string& mime_type, const base::FilePath& filename, const std::vector& data); + void OnWebCustomDataRead(const std::string& mime_type, + const std::vector& data); void ScheduleStartDragDropOperation(); diff --git a/components/exo/seat.cc b/components/exo/seat.cc index fe24cbacbab482..690277a88f1513 100644 --- a/components/exo/seat.cc +++ b/components/exo/seat.cc @@ -170,7 +170,10 @@ void Seat::SetSelection(DataSource* source) { data_read_callback), base::BindOnce(&Seat::OnFilenamesRead, weak_ptr_factory_.GetWeakPtr(), endpoint_type, writer, data_read_callback), - DataSource::ReadFileContentsDataCallback(), data_read_callback); + DataSource::ReadFileContentsDataCallback(), + base::BindOnce(&Seat::OnWebCustomDataRead, weak_ptr_factory_.GetWeakPtr(), + writer, data_read_callback), + data_read_callback); } class Seat::RefCountedScopedClipboardWriter @@ -249,6 +252,16 @@ void Seat::OnFilenamesRead( std::move(callback).Run(); } +void Seat::OnWebCustomDataRead( + scoped_refptr writer, + base::OnceClosure callback, + const std::string& mime_type, + const std::vector& data) { + NOTREACHED() + << "Seat does not support custom data mime types for selections."; + std::move(callback).Run(); +} + void Seat::OnAllReadsFinished( scoped_refptr writer) { // We need to destroy the ScopedClipboardWriter in this call, before diff --git a/components/exo/seat.h b/components/exo/seat.h index 580f8f127fb124..79d369a472d533 100644 --- a/components/exo/seat.h +++ b/components/exo/seat.h @@ -189,6 +189,11 @@ class Seat : public aura::client::FocusChangeObserver, base::OnceClosure callback, const std::string& mime_type, const std::vector& data); + void OnWebCustomDataRead( + scoped_refptr writer, + base::OnceClosure callback, + const std::string& mime_type, + const std::vector& data); void OnAllReadsFinished( scoped_refptr writer); diff --git a/ui/ozone/platform/wayland/host/wayland_data_drag_controller.cc b/ui/ozone/platform/wayland/host/wayland_data_drag_controller.cc index 385819c5a50dc6..a039b40b4cbde4 100644 --- a/ui/ozone/platform/wayland/host/wayland_data_drag_controller.cc +++ b/ui/ozone/platform/wayland/host/wayland_data_drag_controller.cc @@ -125,7 +125,7 @@ bool WaylandDataDragController::StartSession(const OSExchangeData& data, return false; } - // Create new new data source and offers |data|. + // Create new data source and offers |data|. SetOfferedExchangeDataProvider(data); data_source_ = data_device_manager_->CreateSource(this); data_source_->Offer(GetOfferedExchangeDataProvider()->BuildMimeTypesList()); diff --git a/ui/ozone/platform/wayland/host/wayland_exchange_data_provider.cc b/ui/ozone/platform/wayland/host/wayland_exchange_data_provider.cc index e48d1a6f099bf8..51ef4e2aad0318 100644 --- a/ui/ozone/platform/wayland/host/wayland_exchange_data_provider.cc +++ b/ui/ozone/platform/wayland/host/wayland_exchange_data_provider.cc @@ -47,6 +47,8 @@ int MimeTypeToFormat(const std::string& mime_type) { return OSExchangeData::HTML; if (base::StartsWith(mime_type, ui::kMimeTypeOctetStream)) return OSExchangeData::FILE_CONTENTS; + if (mime_type == ui::kMimeTypeWebCustomData) + return OSExchangeData::PICKLED_DATA; return 0; } @@ -259,6 +261,14 @@ bool WaylandExchangeDataProvider::ExtractData(const std::string& mime_type, out_content->append(base::UTF16ToUTF8(data)); return true; } + if (HasCustomFormat(ui::ClipboardFormatType::WebCustomDataType())) { + base::Pickle pickle; + GetPickledData(ui::ClipboardFormatType::WebCustomDataType(), &pickle); + *out_content = std::string(reinterpret_cast(pickle.data()), + pickle.size()); + return true; + } + return false; }