From f09a00d5b0c7c90d2111b211f3f08dfc30186639 Mon Sep 17 00:00:00 2001 From: Maksim Sisov Date: Wed, 5 Dec 2018 15:43:01 +0200 Subject: [PATCH] [DoNotCarryForward] Implement Clipboard for Ozone platforms. This patch provides a general clipboard implementation for Ozone. The initialization happens automatically: Clipboard::Create->ClipboardOzone::ClipboardOzone()-> AsyncClipboardOzone::AsyncClipboardOzone()->ClipboardDelegate::GetInstance(). where ClipboardOzone is a derived class from base::Clipboard, AsyncClipboardOzone is a private helper class of ClipboardOzone, which gets calls from it, makes requests and sends them to ClipboardDelegate. TL;DR: The ClipboardDelegate::GetInstance stores a singleton delegate instance, which is stored automatically once clipboard delegate is created. Each ozone platform, which uses clipboard, is responsible to create own instance of ClipboardDelegate, which communicates with a system clipboard. If a platform does not have own, the ClipboardDelegate::GetInstance creates a FakeClipboardDelegate, which emulates the system clipboard in such a way that it can pass unittests and provide copy/paste functionality within browser. The flow is asynchronous and based on requests.That is, whenever a ClipboardOzone receives a Read/Write/GetMime call, it forwards it to the helper AsyncClipboardOzone class, which then creates a request (used for internal usage and holding data filled by the ClipboardDelegate), calls to the delegate and start an abort timer to make sure the request is not stalled. What is more the clipboard data is cached and removed only when another chunk of data iss written to a system clipboard. And whenever the chromium browser is the selection owner, the cached data is used. Bug: 875168 Test: interactive_ui_tests --gtest_filter=ClipboardTest* components_unittests --gtest_filter=BookmarkUtilsTest* Change-Id: I0101aebe47cf2cac666f0434b6be2a9a11e2418c --- ui/base/BUILD.gn | 21 +- ui/base/clipboard/DEPS | 1 + ui/base/clipboard/clipboard_ozone.cc | 411 ++++++++++++++++++++ ui/base/clipboard/clipboard_ozone.h | 72 ++++ ui/base/clipboard/clipboard_test_template.h | 8 +- ui/ozone/BUILD.gn | 3 + ui/ozone/public/clipboard_delegate.cc | 42 ++ ui/ozone/public/fake_clipboard_delegate.cc | 44 +++ ui/ozone/public/fake_clipboard_delegate.h | 39 ++ ui/ozone/public/platform_clipboard.h | 5 + 10 files changed, 637 insertions(+), 9 deletions(-) create mode 100644 ui/base/clipboard/clipboard_ozone.cc create mode 100644 ui/base/clipboard/clipboard_ozone.h create mode 100644 ui/ozone/public/clipboard_delegate.cc create mode 100644 ui/ozone/public/fake_clipboard_delegate.cc create mode 100644 ui/ozone/public/fake_clipboard_delegate.h diff --git a/ui/base/BUILD.gn b/ui/base/BUILD.gn index 3131e7c91b1d6..b90a90df4353f 100644 --- a/ui/base/BUILD.gn +++ b/ui/base/BUILD.gn @@ -645,12 +645,21 @@ jumbo_component("base") { if (use_aura) { # Aura clipboard. - if (use_x11 && is_desktop_linux) { - sources += [ - "clipboard/clipboard_aura_linux.cc", - "clipboard/clipboard_aurax11.cc", - "clipboard/clipboard_aurax11.h", - ] + if (is_desktop_linux) { + if (use_x11 || use_ozone) { + sources += [ "clipboard/clipboard_aura_linux.cc" ] + } + if (use_ozone) { + sources += [ + "clipboard/clipboard_ozone.cc", + "clipboard/clipboard_ozone.h", + ] + } else if (use_x11) { + sources += [ + "clipboard/clipboard_aurax11.cc", + "clipboard/clipboard_aurax11.h", + ] + } } else if (!is_win) { # This file is used for all non-X11, non-Windows aura Builds. sources += [ diff --git a/ui/base/clipboard/DEPS b/ui/base/clipboard/DEPS index e963fe555f228..4142ca0506862 100644 --- a/ui/base/clipboard/DEPS +++ b/ui/base/clipboard/DEPS @@ -1,4 +1,5 @@ include_rules = [ "+jni", "+third_party/mozilla", + "+ui/ozone/public/clipboard_delegate.h", ] diff --git a/ui/base/clipboard/clipboard_ozone.cc b/ui/base/clipboard/clipboard_ozone.cc new file mode 100644 index 0000000000000..7b007a9db170f --- /dev/null +++ b/ui/base/clipboard/clipboard_ozone.cc @@ -0,0 +1,411 @@ +// Copyright 2018 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 "ui/base/clipboard/clipboard_ozone.h" + +#include + +#include "base/bind.h" +#include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "base/run_loop.h" +#include "base/strings/utf_string_conversions.h" +#include "base/timer/timer.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "ui/base/clipboard/custom_data_helper.h" +#include "ui/gfx/codec/png_codec.h" +#include "ui/ozone/public/platform_clipboard.h" + +namespace ui { + +// A helper class, which uses a request pattern to asynchronously communicate +// with the ozone::PlatformClipboard and fetch clipboard data with mimes +// specified. +class ClipboardOzone::AsyncClipboardOzone { + public: + AsyncClipboardOzone() + : delegate_(PlatformClipboard::GetInstance()), weak_factory_(this) {} + + ~AsyncClipboardOzone() = default; + + std::vector ReadClipboardDataAndWait(ClipboardType type, + const std::string& mime_type) { + // TODO(tonikitoo): add selection support. + if (type == ClipboardType::CLIPBOARD_TYPE_SELECTION) + return std::vector(); + + // We can use a fastpath if we are the owner of the selection. + if (delegate_->IsSelectionOwner()) { + return offered_data_.find(mime_type) != offered_data_.end() + ? offered_data_[mime_type] + : std::vector(); + } + + std::unique_ptr request = + std::make_unique(RequestType::READ); + request->requested_mime_type = mime_type; + ProcessRequestAndWaitForResult(request.get()); + return !request->data_map.empty() ? request->data_map[mime_type] + : std::vector(); + } + + std::vector RequestMimeTypes() { + std::unique_ptr request = + std::make_unique(RequestType::GET_MIME); + ProcessRequestAndWaitForResult(request.get()); + return std::move(request->mime_types); + } + + void OfferData() { + std::unique_ptr request = + std::make_unique(RequestType::OFFER); + request->data_map = offered_data_; + ProcessRequestAndWaitForResult(request.get()); + + ++sequence_number_; + } + + void InsertData(std::vector data, const std::string& mime_type) { + DCHECK(offered_data_.find(mime_type) == offered_data_.end()); + offered_data_[mime_type] = std::move(data); + } + + void ClearOfferedData() { offered_data_.clear(); } + + uint64_t sequence_number() const { return sequence_number_; } + + private: + enum class RequestType { + READ = 0, + OFFER = 1, + GET_MIME = 2, + }; + + // A structure, which holds request data to process inquiries from + // the ClipboardOzone. + struct Request { + explicit Request(RequestType type) : current_type(type) {} + ~Request() = default; + + // Describes the type of the request. + RequestType current_type; + + // A closure that is used to signal the request is processed. + base::OnceClosure request_closure; + + // A data map that stores the result data or offers clipboard data. + PlatformClipboard::DataMap data_map; + + // A requested mime type of the current request. + std::string requested_mime_type; + + // A vector of mime types returned as a result to a request to get available + // mime types. + std::vector mime_types; + + // The time when the request should be aborted. + base::TimeTicks timeout; + }; + + void ProcessRequestAndWaitForResult(Request* request) { + DCHECK(!abort_timer_.IsRunning()); + DCHECK(!pending_request_); + + base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed); + base::TimeTicks timeout = + base::TimeTicks::Now() + base::TimeDelta::FromMilliseconds(1000); + request->request_closure = run_loop.QuitClosure(); + request->timeout = timeout; + + pending_request_ = request; + switch (pending_request_->current_type) { + case (RequestType::READ): + ProcessReadRequest(request); + break; + case (RequestType::OFFER): + ProcessOfferRequest(request); + break; + case (RequestType::GET_MIME): + ProcessGetMimeRequest(request); + break; + default: + NOTREACHED(); + break; + } + + if (!pending_request_) + return; + abort_timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(100), this, + &AsyncClipboardOzone::AbortStaledRequest); + run_loop.Run(); + } + + void AbortStaledRequest() { + base::TimeTicks now = base::TimeTicks::Now(); + if (pending_request_ && pending_request_->timeout >= now) + std::move(pending_request_->request_closure).Run(); + } + + void ProcessReadRequest(Request* request) { + auto callback = base::BindOnce(&AsyncClipboardOzone::OnTextRead, + weak_factory_.GetWeakPtr()); + DCHECK(delegate_); + delegate_->RequestClipboardData(request->requested_mime_type, + &request->data_map, std::move(callback)); + } + + void ProcessOfferRequest(Request* request) { + auto callback = base::BindOnce(&AsyncClipboardOzone::OnOfferDone, + weak_factory_.GetWeakPtr()); + DCHECK(delegate_); + delegate_->OfferClipboardData(request->data_map, std::move(callback)); + } + + void ProcessGetMimeRequest(Request* request) { + auto callback = base::BindOnce(&AsyncClipboardOzone::OnGotMimeTypes, + weak_factory_.GetWeakPtr()); + DCHECK(delegate_); + delegate_->GetAvailableMimeTypes(std::move(callback)); + } + + void OnTextRead(const base::Optional>& data) { + CompleteRequest(); + } + + void OnOfferDone() { CompleteRequest(); } + + void OnGotMimeTypes(const std::vector& mime_types) { + pending_request_->mime_types = std::move(mime_types); + CompleteRequest(); + } + + void CompleteRequest() { + abort_timer_.Stop(); + auto closure = std::move(pending_request_->request_closure); + pending_request_ = nullptr; + std::move(closure).Run(); + } + + // Cached clipboard data, which is pending to be written. Must be cleared on + // every new write to the |delegate_|. + PlatformClipboard::DataMap offered_data_; + + // A current pending request being processed. + Request* pending_request_ = nullptr; + + // Aborts |pending_request| after Request::timeout. + base::RepeatingTimer abort_timer_; + + // Provides communication to a system clipboard under ozone level. + PlatformClipboard* delegate_ = nullptr; + + uint64_t sequence_number_ = 0; + + base::WeakPtrFactory weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(AsyncClipboardOzone); +}; + +// Clipboard factory method. +Clipboard* Clipboard::Create() { + return new ClipboardOzone; +} + +// ClipboardOzone implementation. +ClipboardOzone::ClipboardOzone() { + async_clipboard_ozone_ = + std::make_unique(); +} + +ClipboardOzone::~ClipboardOzone() = default; + +void ClipboardOzone::OnPreShutdown() {} + +uint64_t ClipboardOzone::GetSequenceNumber(ClipboardType type) const { + return async_clipboard_ozone_->sequence_number(); +} + +bool ClipboardOzone::IsFormatAvailable(const FormatType& format, + ClipboardType type) const { + DCHECK(CalledOnValidThread()); + // TODO(tonikitoo): add selection support. + if (type == ClipboardType::CLIPBOARD_TYPE_SELECTION) + return false; + + auto available_types = async_clipboard_ozone_->RequestMimeTypes(); + for (auto mime_type : available_types) { + if (format.ToString() == mime_type) { + return true; + } + } + return false; +} + +void ClipboardOzone::Clear(ClipboardType type) { + async_clipboard_ozone_->ClearOfferedData(); + async_clipboard_ozone_->OfferData(); +} + +void ClipboardOzone::ReadAvailableTypes(ClipboardType type, + std::vector* types, + bool* contains_filenames) const { + DCHECK(CalledOnValidThread()); + types->clear(); + + // TODO(tonikitoo): add selection support. + if (type == ClipboardType::CLIPBOARD_TYPE_SELECTION) + return; + + auto available_types = async_clipboard_ozone_->RequestMimeTypes(); + for (auto mime_type : available_types) + types->push_back(base::UTF8ToUTF16(mime_type)); +} + +void ClipboardOzone::ReadText(ClipboardType type, + base::string16* result) const { + DCHECK(CalledOnValidThread()); + + auto clipboard_data = + async_clipboard_ozone_->ReadClipboardDataAndWait(type, kMimeTypeText); + *result = base::UTF8ToUTF16( + std::string(clipboard_data.begin(), clipboard_data.end())); +} + +void ClipboardOzone::ReadAsciiText(ClipboardType type, + std::string* result) const { + DCHECK(CalledOnValidThread()); + auto clipboard_data = + async_clipboard_ozone_->ReadClipboardDataAndWait(type, kMimeTypeText); + result->assign(clipboard_data.begin(), clipboard_data.end()); +} + +void ClipboardOzone::ReadHTML(ClipboardType type, + base::string16* markup, + std::string* src_url, + uint32_t* fragment_start, + uint32_t* fragment_end) const { + DCHECK(CalledOnValidThread()); + markup->clear(); + if (src_url) + src_url->clear(); + *fragment_start = 0; + *fragment_end = 0; + + auto clipboard_data = + async_clipboard_ozone_->ReadClipboardDataAndWait(type, kMimeTypeHTML); + *markup = base::UTF8ToUTF16( + std::string(clipboard_data.begin(), clipboard_data.end())); + DCHECK(markup->length() <= std::numeric_limits::max()); + *fragment_end = static_cast(markup->length()); +} + +void ClipboardOzone::ReadRTF(ClipboardType type, std::string* result) const { + DCHECK(CalledOnValidThread()); + auto clipboard_data = + async_clipboard_ozone_->ReadClipboardDataAndWait(type, kMimeTypeRTF); + result->assign(clipboard_data.begin(), clipboard_data.end()); +} + +SkBitmap ClipboardOzone::ReadImage(ClipboardType type) const { + DCHECK(CalledOnValidThread()); + auto clipboard_data = + async_clipboard_ozone_->ReadClipboardDataAndWait(type, kMimeTypePNG); + SkBitmap bitmap; + if (gfx::PNGCodec::Decode(&clipboard_data.front(), clipboard_data.size(), + &bitmap)) + return SkBitmap(bitmap); + return SkBitmap(); +} + +void ClipboardOzone::ReadCustomData(ClipboardType clipboard_type, + const base::string16& type, + base::string16* result) const { + DCHECK(CalledOnValidThread()); + auto custom_data = async_clipboard_ozone_->ReadClipboardDataAndWait( + clipboard_type, kMimeTypeWebCustomData); + ui::ReadCustomDataForType(&custom_data.front(), custom_data.size(), type, + result); +} + +void ClipboardOzone::ReadBookmark(base::string16* title, + std::string* url) const { + DCHECK(CalledOnValidThread()); + // TODO(msisov): This was left NOTIMPLEMENTED() in all the Linux platforms. + NOTIMPLEMENTED(); +} + +void ClipboardOzone::ReadData(const FormatType& format, + std::string* result) const { + DCHECK(CalledOnValidThread()); + auto clipboard_data = async_clipboard_ozone_->ReadClipboardDataAndWait( + ClipboardType::CLIPBOARD_TYPE_COPY_PASTE, format.ToString()); + result->assign(clipboard_data.begin(), clipboard_data.end()); +} + +void ClipboardOzone::WriteObjects(ClipboardType type, + const ObjectMap& objects) { + DCHECK(CalledOnValidThread()); + if (type == ClipboardType::CLIPBOARD_TYPE_COPY_PASTE) { + async_clipboard_ozone_->ClearOfferedData(); + + for (const auto& object : objects) + DispatchObject(static_cast(object.first), object.second); + + async_clipboard_ozone_->OfferData(); + } +} + +void ClipboardOzone::WriteText(const char* text_data, size_t text_len) { + std::vector data(text_data, text_data + text_len); + async_clipboard_ozone_->InsertData(std::move(data), kMimeTypeText); +} + +void ClipboardOzone::WriteHTML(const char* markup_data, + size_t markup_len, + const char* url_data, + size_t url_len) { + std::vector data(markup_data, markup_data + markup_len); + async_clipboard_ozone_->InsertData(std::move(data), kMimeTypeHTML); +} + +void ClipboardOzone::WriteRTF(const char* rtf_data, size_t data_len) { + std::vector data(rtf_data, rtf_data + data_len); + async_clipboard_ozone_->InsertData(std::move(data), kMimeTypeRTF); +} + +void ClipboardOzone::WriteBookmark(const char* title_data, + size_t title_len, + const char* url_data, + size_t url_len) { + // Writes a Mozilla url (UTF16: URL, newline, title) + base::string16 bookmark = + base::UTF8ToUTF16(base::StringPiece(url_data, url_len)) + + base::ASCIIToUTF16("\n") + + base::UTF8ToUTF16(base::StringPiece(title_data, title_len)); + + std::vector data( + reinterpret_cast(bookmark.data()), + reinterpret_cast(bookmark.data() + bookmark.size())); + async_clipboard_ozone_->InsertData(std::move(data), kMimeTypeMozillaURL); +} + +void ClipboardOzone::WriteWebSmartPaste() { + async_clipboard_ozone_->InsertData(std::vector(), + kMimeTypeWebkitSmartPaste); +} + +void ClipboardOzone::WriteBitmap(const SkBitmap& bitmap) { + std::vector output; + if (gfx::PNGCodec::FastEncodeBGRASkBitmap(bitmap, false, &output)) + async_clipboard_ozone_->InsertData(std::move(output), kMimeTypePNG); +} + +void ClipboardOzone::WriteData(const FormatType& format, + const char* data_data, + size_t data_len) { + std::vector data(data_data, data_data + data_len); + async_clipboard_ozone_->InsertData(data, format.ToString()); +} + +} // namespace ui diff --git a/ui/base/clipboard/clipboard_ozone.h b/ui/base/clipboard/clipboard_ozone.h new file mode 100644 index 0000000000000..d0c7f5c539948 --- /dev/null +++ b/ui/base/clipboard/clipboard_ozone.h @@ -0,0 +1,72 @@ +// Copyright 2018 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. + +#ifndef UI_BASE_CLIPBOARD_CLIPBOARD_OZONE_H_ +#define UI_BASE_CLIPBOARD_CLIPBOARD_OZONE_H_ + +#include +#include + +#include "base/macros.h" +#include "ui/base/clipboard/clipboard.h" + +namespace ui { + +class ClipboardOzone : public Clipboard { + private: + friend class Clipboard; + + ClipboardOzone(); + ~ClipboardOzone() override; + + // Clipboard overrides: + void OnPreShutdown() override; + uint64_t GetSequenceNumber(ClipboardType type) const override; + bool IsFormatAvailable(const FormatType& format, + ClipboardType type) const override; + void Clear(ClipboardType type) override; + void ReadAvailableTypes(ClipboardType type, + std::vector* types, + bool* contains_filenames) const override; + void ReadText(ClipboardType type, base::string16* result) const override; + void ReadAsciiText(ClipboardType type, std::string* result) const override; + void ReadHTML(ClipboardType type, + base::string16* markup, + std::string* src_url, + uint32_t* fragment_start, + uint32_t* fragment_end) const override; + void ReadRTF(ClipboardType type, std::string* result) const override; + SkBitmap ReadImage(ClipboardType type) const override; + void ReadCustomData(ClipboardType clipboard_type, + const base::string16& type, + base::string16* result) const override; + void ReadBookmark(base::string16* title, std::string* url) const override; + void ReadData(const FormatType& format, std::string* result) const override; + void WriteObjects(ClipboardType type, const ObjectMap& objects) override; + void WriteText(const char* text_data, size_t text_len) override; + void WriteHTML(const char* markup_data, + size_t markup_len, + const char* url_data, + size_t url_len) override; + void WriteRTF(const char* rtf_data, size_t data_len) override; + void WriteBookmark(const char* title_data, + size_t title_len, + const char* url_data, + size_t url_len) override; + void WriteWebSmartPaste() override; + void WriteBitmap(const SkBitmap& bitmap) override; + void WriteData(const FormatType& format, + const char* data_data, + size_t data_len) override; + + class AsyncClipboardOzone; + + std::unique_ptr async_clipboard_ozone_; + + DISALLOW_COPY_AND_ASSIGN(ClipboardOzone); +}; + +} // namespace ui + +#endif // UI_BASE_CLIPBOARD_CLIPBOARD_OZONE_H_ diff --git a/ui/base/clipboard/clipboard_test_template.h b/ui/base/clipboard/clipboard_test_template.h index 1d8d38346746f..6571550fead92 100644 --- a/ui/base/clipboard/clipboard_test_template.h +++ b/ui/base/clipboard/clipboard_test_template.h @@ -188,8 +188,8 @@ TYPED_TEST(ClipboardTest, RTFTest) { EXPECT_EQ(rtf, result); } -// TODO(dnicoara) Enable test once Ozone implements clipboard support: -// crbug.com/361707 +// TODO(msisov, tonikitoo): Enable test once ClipboardOzone implements +// selection support. https://crbug.com/911992 #if defined(OS_LINUX) && !defined(OS_CHROMEOS) && !defined(USE_OZONE) TYPED_TEST(ClipboardTest, MultipleBufferTest) { base::string16 text(ASCIIToUTF16("Standard")), text_result; @@ -375,8 +375,10 @@ TYPED_TEST(ClipboardTest, URLTest) { this->clipboard().ReadAsciiText(CLIPBOARD_TYPE_COPY_PASTE, &ascii_text); EXPECT_EQ(UTF16ToUTF8(url), ascii_text); +// TODO(tonikitoo, msisov): enable back for ClipboardOzone implements +// selection support. https://crbug.com/911992 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) && \ - !defined(OS_CHROMEOS) + !defined(OS_CHROMEOS) && !defined(USE_OZONE) ascii_text.clear(); this->clipboard().ReadAsciiText(CLIPBOARD_TYPE_SELECTION, &ascii_text); EXPECT_EQ(UTF16ToUTF8(url), ascii_text); diff --git a/ui/ozone/BUILD.gn b/ui/ozone/BUILD.gn index ce321ea83e67c..1d44821657632 100644 --- a/ui/ozone/BUILD.gn +++ b/ui/ozone/BUILD.gn @@ -71,8 +71,11 @@ constructor_list_cc_file = "$target_gen_dir/constructor_list.cc" jumbo_component("ozone_base") { sources = [ "ozone_base_export.h", + "public/clipboard_delegate.cc", "public/cursor_factory_ozone.cc", "public/cursor_factory_ozone.h", + "public/fake_clipboard_delegate.cc", + "public/fake_clipboard_delegate.h", "public/gl_ozone.h", "public/gpu_platform_support_host.cc", "public/gpu_platform_support_host.h", diff --git a/ui/ozone/public/clipboard_delegate.cc b/ui/ozone/public/clipboard_delegate.cc new file mode 100644 index 0000000000000..cfdad68b28ca0 --- /dev/null +++ b/ui/ozone/public/clipboard_delegate.cc @@ -0,0 +1,42 @@ +// Copyright 2018 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 "ui/ozone/public/platform_clipboard.h" + +#include "ui/ozone/public/fake_clipboard_delegate.h" + +namespace ui { + +namespace { + +PlatformClipboard* g_delegate_instance = nullptr; + +} // namespace + +PlatformClipboard::PlatformClipboard() { + DCHECK(!g_delegate_instance) + << "Only one instance of PlatformClipboard is allowed."; + g_delegate_instance = this; +} + +PlatformClipboard::~PlatformClipboard() { + DCHECK_EQ(g_delegate_instance, this); + g_delegate_instance = nullptr; +} + +PlatformClipboard* PlatformClipboard::GetInstance() { + if (!g_delegate_instance) { + LOG(ERROR) << "No PlatformClipboard is available. Falling back to " + "FakeClipboardDelegate. Please note that each Ozone platform " + "must provide own PlatformClipboard implementations in order " + "to be able to communicate with a system clipboard."; + std::unique_ptr delegate = + std::make_unique(); + CHECK(g_delegate_instance) << "Unable to create fake clipboard delegate"; + delegate.release(); + } + return g_delegate_instance; +} + +} // namespace ui diff --git a/ui/ozone/public/fake_clipboard_delegate.cc b/ui/ozone/public/fake_clipboard_delegate.cc new file mode 100644 index 0000000000000..0214c4ee9104f --- /dev/null +++ b/ui/ozone/public/fake_clipboard_delegate.cc @@ -0,0 +1,44 @@ +// Copyright 2018 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 "ui/ozone/public/fake_clipboard_delegate.h" + +namespace ui { + +FakeClipboardDelegate::FakeClipboardDelegate() = default; + +FakeClipboardDelegate::~FakeClipboardDelegate() = default; + +void FakeClipboardDelegate::OfferClipboardData(const DataMap& data_map, + OfferDataClosure callback) { + offered_data_map_ = data_map; + std::move(callback).Run(); +} + +void FakeClipboardDelegate::RequestClipboardData(const std::string& mime_type, + DataMap* data_map, + RequestDataClosure callback) { + auto it = offered_data_map_.find(mime_type); + if (it == offered_data_map_.end()) { + std::move(callback).Run(base::Optional()); + return; + } + *data_map = offered_data_map_; + std::move(callback).Run(std::move(it->second)); +} + +void FakeClipboardDelegate::GetAvailableMimeTypes( + GetMimeTypesClosure callback) { + std::vector mime_types; + for (const auto& item : offered_data_map_) { + mime_types.push_back(item.first); + } + std::move(callback).Run(std::move(mime_types)); +} + +bool FakeClipboardDelegate::IsSelectionOwner() { + return !offered_data_map_.empty(); +} + +} // namespace ui diff --git a/ui/ozone/public/fake_clipboard_delegate.h b/ui/ozone/public/fake_clipboard_delegate.h new file mode 100644 index 0000000000000..bdba981d7b3d1 --- /dev/null +++ b/ui/ozone/public/fake_clipboard_delegate.h @@ -0,0 +1,39 @@ +// Copyright 2018 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. + +#ifndef UI_OZONE_PUBLIC_FAKE_CLIPBOARD_DELEGATE_H_ +#define UI_OZONE_PUBLIC_FAKE_CLIPBOARD_DELEGATE_H_ + +#include "base/callback.h" +#include "base/macros.h" +#include "base/memory/scoped_refptr.h" +#include "ui/ozone/public/platform_clipboard.h" + +namespace ui { + +// Fake clipboard delegate, which just stores offered clipboard data and sends +// it back on requests. It's created automatically if ozone platforms do not +// implement and create PlatformClipboard. +class FakeClipboardDelegate : public PlatformClipboard { + public: + FakeClipboardDelegate(); + ~FakeClipboardDelegate() override; + + void OfferClipboardData(const DataMap& data_map, + OfferDataClosure callback) override; + void RequestClipboardData(const std::string& mime_type, + DataMap* data_map, + RequestDataClosure callback) override; + void GetAvailableMimeTypes(GetMimeTypesClosure callback) override; + bool IsSelectionOwner() override; + + private: + PlatformClipboard::DataMap offered_data_map_; + + DISALLOW_COPY_AND_ASSIGN(FakeClipboardDelegate); +}; + +} // namespace ui + +#endif // UI_OZONE_PUBLIC_CLIPBOARD_DELEGATE_H_ diff --git a/ui/ozone/public/platform_clipboard.h b/ui/ozone/public/platform_clipboard.h index df5940924b161..602116907d7cf 100644 --- a/ui/ozone/public/platform_clipboard.h +++ b/ui/ozone/public/platform_clipboard.h @@ -21,11 +21,16 @@ namespace ui { // class OZONE_BASE_EXPORT PlatformClipboard { public: + PlatformClipboard(); + virtual ~PlatformClipboard(); + // DataMap is a map from "mime type" to associated data, whereas // the data can be organized differently for each mime type. using Data = std::vector; using DataMap = std::unordered_map; + static PlatformClipboard* GetInstance(); + // Offers a given clipboard data 'data_map' to the host system clipboard. // // It is common that host clipboard implementations simply get offered