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; }