| // Copyright (c) 2012 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_non_backed.h" |
| |
| #include <stdint.h> |
| |
| #include <limits> |
| #include <list> |
| #include <memory> |
| #include <set> |
| #include <utility> |
| |
| #include "base/check_op.h" |
| #include "base/containers/contains.h" |
| #include "base/files/file_path.h" |
| #include "base/memory/ptr_util.h" |
| #include "base/no_destructor.h" |
| #include "base/notreached.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/synchronization/lock.h" |
| #include "build/chromeos_buildflags.h" |
| #include "skia/ext/skia_utils_base.h" |
| #include "third_party/skia/include/core/SkBitmap.h" |
| #include "ui/base/clipboard/clipboard_constants.h" |
| #include "ui/base/clipboard/clipboard_data.h" |
| #include "ui/base/clipboard/clipboard_format_type.h" |
| #include "ui/base/clipboard/clipboard_metrics.h" |
| #include "ui/base/clipboard/clipboard_monitor.h" |
| #include "ui/base/clipboard/custom_data_helper.h" |
| #include "ui/base/data_transfer_policy/data_transfer_endpoint.h" |
| #include "ui/base/data_transfer_policy/data_transfer_policy_controller.h" |
| #include "ui/gfx/geometry/size.h" |
| |
| namespace ui { |
| |
| namespace { |
| |
| using InstanceRegistry = std::set<const ClipboardNonBacked*, std::less<>>; |
| // Returns the registry which tracks all instances of ClipboardNonBacked in |
| // existence. This allows us to determine if any arbitrary Clipboard pointer in |
| // fact points to a ClipboardNonBacked instance. Only if a pointer exists in |
| // this registry is it safe to cast to ClipboardNonBacked*. |
| InstanceRegistry* GetInstanceRegistry() { |
| static base::NoDestructor<InstanceRegistry> registry; |
| return registry.get(); |
| } |
| |
| // The ClipboardNonBacked instance registry can be accessed by multiple threads. |
| // Any inspection/modification of the instance registry must only be performed |
| // while this lock is held. |
| base::Lock& GetInstanceRegistryLock() { |
| static base::NoDestructor<base::Lock> registry_lock; |
| return *registry_lock; |
| } |
| |
| // Registers the specified |clipboard| as an instance of ClipboardNonBacked. |
| // Registration should occur during |clipboard| construction and registration |
| // should be maintained until |clipboard| is destroyed. This allows us to check |
| // if any arbitrary Clipboard* is safe to cast. |
| void RegisterInstance(const ClipboardNonBacked* clipboard) { |
| base::AutoLock lock(GetInstanceRegistryLock()); |
| GetInstanceRegistry()->insert(clipboard); |
| } |
| |
| // Unregisters the specified |clipboard| as a instance of ClipboardNonBacked. |
| // This should only be done when destroying |clipboard|. |
| void UnregisterInstance(const ClipboardNonBacked* clipboard) { |
| base::AutoLock lock(GetInstanceRegistryLock()); |
| GetInstanceRegistry()->erase(clipboard); |
| } |
| |
| // Checks if |clipboard| is registered as an instance of ClipboardNonBacked. |
| // Only if this method returns true is it safe to cast |clipboard| to |
| // ClipboardNonBacked*. |
| bool IsRegisteredInstance(const Clipboard* clipboard) { |
| base::AutoLock lock(GetInstanceRegistryLock()); |
| return base::Contains(*GetInstanceRegistry(), clipboard); |
| } |
| |
| } // namespace |
| |
| // Simple, internal implementation of a clipboard, handling things like format |
| // conversion, sequence numbers, etc. |
| class ClipboardInternal { |
| public: |
| ClipboardInternal() = default; |
| ClipboardInternal(const ClipboardInternal&) = delete; |
| ClipboardInternal& operator=(const ClipboardInternal&) = delete; |
| ~ClipboardInternal() = default; |
| |
| void Clear() { |
| sequence_number_ = ClipboardSequenceNumberToken(); |
| data_.reset(); |
| ClipboardMonitor::GetInstance()->NotifyClipboardDataChanged(); |
| } |
| |
| const ClipboardSequenceNumberToken& sequence_number() const { |
| return sequence_number_; |
| } |
| |
| // Returns the current clipboard data, which may be nullptr if nothing has |
| // been written since the last Clear(). |
| const ClipboardData* GetData() const { return data_.get(); } |
| |
| // Returns true if the data on top of the clipboard stack has format |format| |
| // or another format that can be converted to |format|. |
| bool IsFormatAvailable(ClipboardInternalFormat format) const { |
| if (format == ClipboardInternalFormat::kText) { |
| return HasFormat(ClipboardInternalFormat::kText) || |
| HasFormat(ClipboardInternalFormat::kBookmark); |
| } |
| return HasFormat(format); |
| } |
| |
| // Reads text from the ClipboardData. |
| void ReadText(std::u16string* result) const { |
| std::string utf8_result; |
| ReadAsciiText(&utf8_result); |
| *result = base::UTF8ToUTF16(utf8_result); |
| } |
| |
| // Reads ASCII text from the ClipboardData. |
| void ReadAsciiText(std::string* result) const { |
| result->clear(); |
| const ClipboardData* data = GetData(); |
| if (!data) |
| return; |
| if (HasFormat(ClipboardInternalFormat::kText)) |
| *result = data->text(); |
| else if (HasFormat(ClipboardInternalFormat::kHtml)) |
| *result = data->markup_data(); |
| else if (HasFormat(ClipboardInternalFormat::kBookmark)) |
| *result = data->bookmark_url(); |
| } |
| |
| // Reads HTML from the ClipboardData. |
| void ReadHTML(std::u16string* markup, |
| std::string* src_url, |
| uint32_t* fragment_start, |
| uint32_t* fragment_end) const { |
| markup->clear(); |
| if (src_url) |
| src_url->clear(); |
| *fragment_start = 0; |
| *fragment_end = 0; |
| |
| if (!HasFormat(ClipboardInternalFormat::kHtml)) |
| return; |
| |
| const ClipboardData* data = GetData(); |
| *markup = base::UTF8ToUTF16(data->markup_data()); |
| *src_url = data->url(); |
| |
| *fragment_start = 0; |
| DCHECK_LE(markup->length(), std::numeric_limits<uint32_t>::max()); |
| *fragment_end = static_cast<uint32_t>(markup->length()); |
| } |
| |
| // Reads SVG from the ClipboardData. |
| void ReadSvg(std::u16string* markup) const { |
| markup->clear(); |
| |
| if (!HasFormat(ClipboardInternalFormat::kSvg)) |
| return; |
| |
| const ClipboardData* data = GetData(); |
| *markup = base::UTF8ToUTF16(data->svg_data()); |
| |
| DCHECK_LE(markup->length(), std::numeric_limits<uint32_t>::max()); |
| } |
| |
| // Reads RTF from the ClipboardData. |
| void ReadRTF(std::string* result) const { |
| result->clear(); |
| const ClipboardData* data = GetData(); |
| if (!HasFormat(ClipboardInternalFormat::kRtf)) |
| return; |
| |
| *result = data->rtf_data(); |
| } |
| |
| // Reads png from the ClipboardData. |
| std::vector<uint8_t> ReadPng() const { |
| if (!HasFormat(ClipboardInternalFormat::kPng)) |
| return std::vector<uint8_t>(); |
| |
| return GetData()->png(); |
| } |
| |
| // Reads image from the ClipboardData. |
| SkBitmap ReadImage() const { |
| SkBitmap img; |
| if (!HasFormat(ClipboardInternalFormat::kPng)) |
| return img; |
| |
| // A shallow copy should be fine here, but just to be safe... |
| const SkBitmap& clipboard_bitmap = GetData()->bitmap(); |
| if (img.tryAllocPixels(clipboard_bitmap.info())) { |
| clipboard_bitmap.readPixels(img.info(), img.getPixels(), img.rowBytes(), |
| 0, 0); |
| } |
| return img; |
| } |
| |
| // Reads data of type |type| from the ClipboardData. |
| void ReadCustomData(const std::u16string& type, |
| std::u16string* result) const { |
| result->clear(); |
| const ClipboardData* data = GetData(); |
| if (!HasFormat(ClipboardInternalFormat::kCustom)) |
| return; |
| |
| ReadCustomDataForType(data->custom_data_data().c_str(), |
| data->custom_data_data().size(), type, result); |
| } |
| |
| // Reads filenames from the ClipboardData. |
| const std::vector<ui::FileInfo>& ReadFilenames() const { |
| return GetData()->filenames(); |
| } |
| |
| // Reads bookmark from the ClipboardData. |
| void ReadBookmark(std::u16string* title, std::string* url) const { |
| if (title) |
| title->clear(); |
| if (url) |
| url->clear(); |
| if (!HasFormat(ClipboardInternalFormat::kBookmark)) |
| return; |
| |
| const ClipboardData* data = GetData(); |
| if (title) |
| *title = base::UTF8ToUTF16(data->bookmark_title()); |
| if (url) |
| *url = data->bookmark_url(); |
| } |
| |
| void ReadData(const std::string& type, std::string* result) const { |
| result->clear(); |
| const ClipboardData* data = GetData(); |
| if (!HasFormat(ClipboardInternalFormat::kCustom) || |
| type != data->custom_data_format()) |
| return; |
| *result = data->custom_data_data(); |
| } |
| |
| // Writes |data| to the ClipboardData and returns the previous data. |
| std::unique_ptr<ClipboardData> WriteData( |
| std::unique_ptr<ClipboardData> data) { |
| DCHECK(data); |
| std::unique_ptr<ClipboardData> previous_data = std::move(data_); |
| data_ = std::move(data); |
| sequence_number_ = ClipboardSequenceNumberToken(); |
| ClipboardMonitor::GetInstance()->NotifyClipboardDataChanged(); |
| return previous_data; |
| } |
| |
| bool IsReadAllowed(const DataTransferEndpoint* data_dst) const { |
| DataTransferPolicyController* policy_controller = |
| DataTransferPolicyController::Get(); |
| auto* data = GetData(); |
| if (!policy_controller || !data) |
| return true; |
| return policy_controller->IsClipboardReadAllowed(data->source(), data_dst, |
| data->size()); |
| } |
| |
| private: |
| // True if the ClipboardData has format |format|. |
| bool HasFormat(ClipboardInternalFormat format) const { |
| const ClipboardData* data = GetData(); |
| return data ? data->format() & static_cast<int>(format) : false; |
| } |
| |
| // Current ClipboardData. |
| std::unique_ptr<ClipboardData> data_; |
| |
| // Sequence number uniquely identifying clipboard state. |
| ClipboardSequenceNumberToken sequence_number_; |
| }; |
| |
| // Helper class to build a ClipboardData object and write it to clipboard. |
| class ClipboardDataBuilder { |
| public: |
| // If |data_src| is nullptr, this means that the data source isn't |
| // confidential and the data can be pasted in any document. |
| static void CommitToClipboard( |
| ClipboardInternal* clipboard, |
| std::unique_ptr<DataTransferEndpoint> data_src) { |
| ClipboardData* data = GetCurrentData(); |
| data->set_source(std::move(data_src)); |
| clipboard->WriteData(TakeCurrentData()); |
| } |
| |
| static void WriteText(const char* text_data, size_t text_len) { |
| ClipboardData* data = GetCurrentData(); |
| data->set_text(std::string(text_data, text_len)); |
| } |
| |
| static void WriteHTML(const char* markup_data, |
| size_t markup_len, |
| const char* url_data, |
| size_t url_len) { |
| ClipboardData* data = GetCurrentData(); |
| data->set_markup_data(std::string(markup_data, markup_len)); |
| data->set_url(std::string(url_data, url_len)); |
| } |
| |
| static void WriteSvg(const char* markup_data, size_t markup_len) { |
| ClipboardData* data = GetCurrentData(); |
| data->set_svg_data(std::string(markup_data, markup_len)); |
| } |
| |
| static void WriteRTF(const char* rtf_data, size_t rtf_len) { |
| ClipboardData* data = GetCurrentData(); |
| data->SetRTFData(std::string(rtf_data, rtf_len)); |
| } |
| |
| static void WriteFilenames(std::vector<ui::FileInfo> filenames) { |
| ClipboardData* data = GetCurrentData(); |
| data->set_filenames(std::move(filenames)); |
| } |
| |
| static void WriteBookmark(const char* title_data, |
| size_t title_len, |
| const char* url_data, |
| size_t url_len) { |
| ClipboardData* data = GetCurrentData(); |
| data->set_bookmark_title(std::string(title_data, title_len)); |
| data->set_bookmark_url(std::string(url_data, url_len)); |
| } |
| |
| static void WriteWebSmartPaste() { |
| ClipboardData* data = GetCurrentData(); |
| data->set_web_smart_paste(true); |
| } |
| |
| static void WriteBitmap(const SkBitmap& bitmap) { |
| ClipboardData* data = GetCurrentData(); |
| data->SetBitmapData(bitmap); |
| } |
| |
| static void WriteData(const std::string& format, |
| const char* data_data, |
| size_t data_len) { |
| ClipboardData* data = GetCurrentData(); |
| data->SetCustomData(format, std::string(data_data, data_len)); |
| } |
| |
| private: |
| static ClipboardData* GetCurrentData() { |
| if (!current_data_) |
| current_data_ = new ClipboardData; |
| return current_data_; |
| } |
| |
| static std::unique_ptr<ClipboardData> TakeCurrentData() { |
| std::unique_ptr<ClipboardData> data = base::WrapUnique(GetCurrentData()); |
| current_data_ = nullptr; |
| return data; |
| } |
| // This is a raw pointer instead of a std::unique_ptr to avoid adding a |
| // static initializer. |
| static ClipboardData* current_data_; |
| }; |
| |
| ClipboardData* ClipboardDataBuilder::current_data_ = nullptr; |
| |
| // static |
| ClipboardNonBacked* ClipboardNonBacked::GetForCurrentThread() { |
| auto* clipboard = Clipboard::GetForCurrentThread(); |
| |
| // Ensure type safety. In tests the instance may not be registered. |
| if (!IsRegisteredInstance(clipboard)) |
| return nullptr; |
| |
| return static_cast<ClipboardNonBacked*>(clipboard); |
| } |
| |
| // ClipboardNonBacked implementation. |
| ClipboardNonBacked::ClipboardNonBacked() |
| : clipboard_internal_(std::make_unique<ClipboardInternal>()) { |
| DCHECK(CalledOnValidThread()); |
| RegisterInstance(this); |
| } |
| |
| ClipboardNonBacked::~ClipboardNonBacked() { |
| DCHECK(CalledOnValidThread()); |
| UnregisterInstance(this); |
| } |
| |
| const ClipboardData* ClipboardNonBacked::GetClipboardData( |
| DataTransferEndpoint* data_dst) const { |
| DCHECK(CalledOnValidThread()); |
| |
| if (!clipboard_internal_->IsReadAllowed(data_dst)) |
| return nullptr; |
| |
| return clipboard_internal_->GetData(); |
| } |
| |
| std::unique_ptr<ClipboardData> ClipboardNonBacked::WriteClipboardData( |
| std::unique_ptr<ClipboardData> data) { |
| DCHECK(CalledOnValidThread()); |
| return clipboard_internal_->WriteData(std::move(data)); |
| } |
| |
| void ClipboardNonBacked::OnPreShutdown() {} |
| |
| DataTransferEndpoint* ClipboardNonBacked::GetSource( |
| ClipboardBuffer buffer) const { |
| const ClipboardData* data = clipboard_internal_->GetData(); |
| return data ? data->source() : nullptr; |
| } |
| |
| const ClipboardSequenceNumberToken& ClipboardNonBacked::GetSequenceNumber( |
| ClipboardBuffer buffer) const { |
| DCHECK(CalledOnValidThread()); |
| return clipboard_internal_->sequence_number(); |
| } |
| |
| bool ClipboardNonBacked::IsFormatAvailable( |
| const ClipboardFormatType& format, |
| ClipboardBuffer buffer, |
| const DataTransferEndpoint* data_dst) const { |
| DCHECK(CalledOnValidThread()); |
| DCHECK(IsSupportedClipboardBuffer(buffer)); |
| |
| if (!clipboard_internal_->IsReadAllowed(data_dst)) |
| return false; |
| |
| if (format == ClipboardFormatType::PlainTextType() || |
| format == ClipboardFormatType::UrlType()) |
| return clipboard_internal_->IsFormatAvailable( |
| ClipboardInternalFormat::kText); |
| if (format == ClipboardFormatType::HtmlType()) |
| return clipboard_internal_->IsFormatAvailable( |
| ClipboardInternalFormat::kHtml); |
| if (format == ClipboardFormatType::SvgType()) |
| return clipboard_internal_->IsFormatAvailable( |
| ClipboardInternalFormat::kSvg); |
| if (format == ClipboardFormatType::RtfType()) |
| return clipboard_internal_->IsFormatAvailable( |
| ClipboardInternalFormat::kRtf); |
| if (format == ClipboardFormatType::PngType() || |
| format == ClipboardFormatType::BitmapType()) |
| return clipboard_internal_->IsFormatAvailable( |
| ClipboardInternalFormat::kPng); |
| if (format == ClipboardFormatType::WebKitSmartPasteType()) |
| return clipboard_internal_->IsFormatAvailable( |
| ClipboardInternalFormat::kWeb); |
| // Only support filenames if chrome://flags#clipboard-filenames is enabled. |
| if (format == ClipboardFormatType::FilenamesType()) |
| return clipboard_internal_->IsFormatAvailable( |
| ClipboardInternalFormat::kFilenames); |
| const ClipboardData* data = clipboard_internal_->GetData(); |
| return data && data->custom_data_format() == format.GetName(); |
| } |
| |
| void ClipboardNonBacked::Clear(ClipboardBuffer buffer) { |
| DCHECK(CalledOnValidThread()); |
| DCHECK(IsSupportedClipboardBuffer(buffer)); |
| clipboard_internal_->Clear(); |
| } |
| |
| void ClipboardNonBacked::ReadAvailableTypes( |
| ClipboardBuffer buffer, |
| const DataTransferEndpoint* data_dst, |
| std::vector<std::u16string>* types) const { |
| DCHECK(CalledOnValidThread()); |
| DCHECK(types); |
| |
| if (!clipboard_internal_->IsReadAllowed(data_dst)) |
| return; |
| |
| types->clear(); |
| if (IsFormatAvailable(ClipboardFormatType::PlainTextType(), buffer, data_dst)) |
| types->push_back( |
| base::UTF8ToUTF16(ClipboardFormatType::PlainTextType().GetName())); |
| if (IsFormatAvailable(ClipboardFormatType::HtmlType(), buffer, data_dst)) |
| types->push_back( |
| base::UTF8ToUTF16(ClipboardFormatType::HtmlType().GetName())); |
| if (IsFormatAvailable(ClipboardFormatType::RtfType(), buffer, data_dst)) |
| types->push_back( |
| base::UTF8ToUTF16(ClipboardFormatType::RtfType().GetName())); |
| if (IsFormatAvailable(ClipboardFormatType::BitmapType(), buffer, data_dst)) |
| types->push_back(base::UTF8ToUTF16(kMimeTypePNG)); |
| if (IsFormatAvailable(ClipboardFormatType::FilenamesType(), buffer, data_dst)) |
| types->push_back(base::UTF8ToUTF16(kMimeTypeURIList)); |
| |
| if (clipboard_internal_->IsFormatAvailable( |
| ClipboardInternalFormat::kCustom) && |
| clipboard_internal_->GetData()) { |
| ReadCustomDataTypes( |
| clipboard_internal_->GetData()->custom_data_data().c_str(), |
| clipboard_internal_->GetData()->custom_data_data().size(), types); |
| } |
| } |
| |
| std::vector<std::u16string> |
| ClipboardNonBacked::ReadAvailablePlatformSpecificFormatNames( |
| ClipboardBuffer buffer, |
| const DataTransferEndpoint* data_dst) const { |
| DCHECK(CalledOnValidThread()); |
| |
| std::vector<std::u16string> types; |
| |
| if (!clipboard_internal_->IsReadAllowed(data_dst)) |
| return types; |
| |
| // Includes all non-pickled AvailableTypes. |
| if (IsFormatAvailable(ClipboardFormatType::PlainTextType(), buffer, |
| data_dst)) { |
| types.push_back( |
| base::UTF8ToUTF16(ClipboardFormatType::PlainTextType().GetName())); |
| } |
| if (IsFormatAvailable(ClipboardFormatType::HtmlType(), buffer, data_dst)) { |
| types.push_back( |
| base::UTF8ToUTF16(ClipboardFormatType::HtmlType().GetName())); |
| } |
| if (IsFormatAvailable(ClipboardFormatType::RtfType(), buffer, data_dst)) { |
| types.push_back( |
| base::UTF8ToUTF16(ClipboardFormatType::RtfType().GetName())); |
| } |
| if (IsFormatAvailable(ClipboardFormatType::BitmapType(), buffer, data_dst)) { |
| types.push_back(base::UTF8ToUTF16(kMimeTypePNG)); |
| } |
| |
| return types; |
| } |
| |
| void ClipboardNonBacked::ReadText(ClipboardBuffer buffer, |
| const DataTransferEndpoint* data_dst, |
| std::u16string* result) const { |
| DCHECK(CalledOnValidThread()); |
| |
| if (!clipboard_internal_->IsReadAllowed(data_dst)) |
| return; |
| |
| RecordRead(ClipboardFormatMetric::kText); |
| clipboard_internal_->ReadText(result); |
| |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| ClipboardMonitor::GetInstance()->NotifyClipboardDataRead(); |
| #endif |
| } |
| |
| void ClipboardNonBacked::ReadAsciiText(ClipboardBuffer buffer, |
| const DataTransferEndpoint* data_dst, |
| std::string* result) const { |
| DCHECK(CalledOnValidThread()); |
| |
| if (!clipboard_internal_->IsReadAllowed(data_dst)) |
| return; |
| |
| RecordRead(ClipboardFormatMetric::kText); |
| clipboard_internal_->ReadAsciiText(result); |
| |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| ClipboardMonitor::GetInstance()->NotifyClipboardDataRead(); |
| #endif |
| } |
| |
| void ClipboardNonBacked::ReadHTML(ClipboardBuffer buffer, |
| const DataTransferEndpoint* data_dst, |
| std::u16string* markup, |
| std::string* src_url, |
| uint32_t* fragment_start, |
| uint32_t* fragment_end) const { |
| DCHECK(CalledOnValidThread()); |
| |
| if (!clipboard_internal_->IsReadAllowed(data_dst)) |
| return; |
| |
| RecordRead(ClipboardFormatMetric::kHtml); |
| clipboard_internal_->ReadHTML(markup, src_url, fragment_start, fragment_end); |
| |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| ClipboardMonitor::GetInstance()->NotifyClipboardDataRead(); |
| #endif |
| } |
| |
| void ClipboardNonBacked::ReadSvg(ClipboardBuffer buffer, |
| const DataTransferEndpoint* data_dst, |
| std::u16string* result) const { |
| DCHECK(CalledOnValidThread()); |
| |
| if (!clipboard_internal_->IsReadAllowed(data_dst)) |
| return; |
| |
| RecordRead(ClipboardFormatMetric::kSvg); |
| clipboard_internal_->ReadSvg(result); |
| } |
| |
| void ClipboardNonBacked::ReadRTF(ClipboardBuffer buffer, |
| const DataTransferEndpoint* data_dst, |
| std::string* result) const { |
| DCHECK(CalledOnValidThread()); |
| |
| if (!clipboard_internal_->IsReadAllowed(data_dst)) |
| return; |
| |
| RecordRead(ClipboardFormatMetric::kRtf); |
| clipboard_internal_->ReadRTF(result); |
| |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| ClipboardMonitor::GetInstance()->NotifyClipboardDataRead(); |
| #endif |
| } |
| |
| void ClipboardNonBacked::ReadPng(ClipboardBuffer buffer, |
| const DataTransferEndpoint* data_dst, |
| ReadPngCallback callback) const { |
| DCHECK(CalledOnValidThread()); |
| |
| if (!clipboard_internal_->IsReadAllowed(data_dst)) { |
| std::move(callback).Run(std::vector<uint8_t>()); |
| return; |
| } |
| |
| RecordRead(ClipboardFormatMetric::kPng); |
| std::move(callback).Run(clipboard_internal_->ReadPng()); |
| |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| ClipboardMonitor::GetInstance()->NotifyClipboardDataRead(); |
| #endif |
| } |
| |
| void ClipboardNonBacked::ReadImage(ClipboardBuffer buffer, |
| const DataTransferEndpoint* data_dst, |
| ReadImageCallback callback) const { |
| DCHECK(CalledOnValidThread()); |
| |
| if (!clipboard_internal_->IsReadAllowed(data_dst)) { |
| std::move(callback).Run(SkBitmap()); |
| return; |
| } |
| |
| RecordRead(ClipboardFormatMetric::kImage); |
| std::move(callback).Run(clipboard_internal_->ReadImage()); |
| |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| ClipboardMonitor::GetInstance()->NotifyClipboardDataRead(); |
| #endif |
| } |
| |
| void ClipboardNonBacked::ReadCustomData(ClipboardBuffer buffer, |
| const std::u16string& type, |
| const DataTransferEndpoint* data_dst, |
| std::u16string* result) const { |
| DCHECK(CalledOnValidThread()); |
| |
| if (!clipboard_internal_->IsReadAllowed(data_dst)) |
| return; |
| |
| RecordRead(ClipboardFormatMetric::kCustomData); |
| clipboard_internal_->ReadCustomData(type, result); |
| |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| ClipboardMonitor::GetInstance()->NotifyClipboardDataRead(); |
| #endif |
| } |
| |
| void ClipboardNonBacked::ReadFilenames( |
| ClipboardBuffer buffer, |
| const DataTransferEndpoint* data_dst, |
| std::vector<ui::FileInfo>* result) const { |
| DCHECK(CalledOnValidThread()); |
| |
| if (!clipboard_internal_->IsReadAllowed(data_dst)) |
| return; |
| |
| RecordRead(ClipboardFormatMetric::kFilenames); |
| *result = clipboard_internal_->ReadFilenames(); |
| |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| ClipboardMonitor::GetInstance()->NotifyClipboardDataRead(); |
| #endif |
| } |
| |
| void ClipboardNonBacked::ReadBookmark(const DataTransferEndpoint* data_dst, |
| std::u16string* title, |
| std::string* url) const { |
| DCHECK(CalledOnValidThread()); |
| |
| if (!clipboard_internal_->IsReadAllowed(data_dst)) |
| return; |
| |
| RecordRead(ClipboardFormatMetric::kBookmark); |
| clipboard_internal_->ReadBookmark(title, url); |
| |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| ClipboardMonitor::GetInstance()->NotifyClipboardDataRead(); |
| #endif |
| } |
| |
| void ClipboardNonBacked::ReadData(const ClipboardFormatType& format, |
| const DataTransferEndpoint* data_dst, |
| std::string* result) const { |
| DCHECK(CalledOnValidThread()); |
| |
| if (!clipboard_internal_->IsReadAllowed(data_dst)) |
| return; |
| |
| RecordRead(ClipboardFormatMetric::kData); |
| clipboard_internal_->ReadData(format.GetName(), result); |
| |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| ClipboardMonitor::GetInstance()->NotifyClipboardDataRead(); |
| #endif |
| } |
| |
| #if defined(USE_OZONE) |
| bool ClipboardNonBacked::IsSelectionBufferAvailable() const { |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| return false; |
| #else |
| return true; |
| #endif |
| } |
| #endif // defined(USE_OZONE) |
| |
| void ClipboardNonBacked::WritePortableAndPlatformRepresentations( |
| ClipboardBuffer buffer, |
| const ObjectMap& objects, |
| std::vector<Clipboard::PlatformRepresentation> platform_representations, |
| std::unique_ptr<DataTransferEndpoint> data_src) { |
| DCHECK(CalledOnValidThread()); |
| DCHECK(IsSupportedClipboardBuffer(buffer)); |
| |
| DispatchPlatformRepresentations(std::move(platform_representations)); |
| for (const auto& object : objects) |
| DispatchPortableRepresentation(object.first, object.second); |
| |
| ClipboardDataBuilder::CommitToClipboard(clipboard_internal_.get(), |
| std::move(data_src)); |
| } |
| |
| void ClipboardNonBacked::WriteText(const char* text_data, size_t text_len) { |
| ClipboardDataBuilder::WriteText(text_data, text_len); |
| } |
| |
| void ClipboardNonBacked::WriteHTML(const char* markup_data, |
| size_t markup_len, |
| const char* url_data, |
| size_t url_len) { |
| ClipboardDataBuilder::WriteHTML(markup_data, markup_len, url_data, url_len); |
| } |
| |
| void ClipboardNonBacked::WriteSvg(const char* markup_data, size_t markup_len) { |
| ClipboardDataBuilder::WriteSvg(markup_data, markup_len); |
| } |
| |
| void ClipboardNonBacked::WriteRTF(const char* rtf_data, size_t data_len) { |
| ClipboardDataBuilder::WriteRTF(rtf_data, data_len); |
| } |
| |
| void ClipboardNonBacked::WriteFilenames(std::vector<ui::FileInfo> filenames) { |
| ClipboardDataBuilder::WriteFilenames(std::move(filenames)); |
| } |
| |
| void ClipboardNonBacked::WriteBookmark(const char* title_data, |
| size_t title_len, |
| const char* url_data, |
| size_t url_len) { |
| ClipboardDataBuilder::WriteBookmark(title_data, title_len, url_data, url_len); |
| } |
| |
| void ClipboardNonBacked::WriteWebSmartPaste() { |
| ClipboardDataBuilder::WriteWebSmartPaste(); |
| } |
| |
| void ClipboardNonBacked::WriteBitmap(const SkBitmap& bitmap) { |
| ClipboardDataBuilder::WriteBitmap(bitmap); |
| } |
| |
| void ClipboardNonBacked::WriteData(const ClipboardFormatType& format, |
| const char* data_data, |
| size_t data_len) { |
| ClipboardDataBuilder::WriteData(format.GetName(), data_data, data_len); |
| } |
| |
| } // namespace ui |