diff options
Diffstat (limited to 'chromium/ui/base/clipboard')
20 files changed, 570 insertions, 359 deletions
diff --git a/chromium/ui/base/clipboard/BUILD.gn b/chromium/ui/base/clipboard/BUILD.gn index 61570cc1f2e..b36512c4c36 100644 --- a/chromium/ui/base/clipboard/BUILD.gn +++ b/chromium/ui/base/clipboard/BUILD.gn @@ -20,29 +20,30 @@ jumbo_component("clipboard_types") { "clipboard_constants.h", ] + if (!is_ios) { + sources += [ "clipboard_format_type.h" ] + } + if (is_android) { sources += [ "clipboard_format_type_android.cc" ] } if (is_mac) { - sources += [ - "clipboard_constants_mac.mm", - "clipboard_format_type_mac.mm", - ] + sources += [ "clipboard_format_type_mac.mm" ] + } + + if (is_mac || is_ios) { + sources += [ "clipboard_constants_mac.mm" ] } if (is_win) { sources += [ "clipboard_format_type_win.cc" ] } - if (!is_ios) { - if (use_aura) { - if ((use_x11 && is_desktop_linux) || !is_win) { - sources += [ "clipboard_format_type_aura.cc" ] - } + if (use_aura) { + if ((use_x11 && is_desktop_linux) || !is_win) { + sources += [ "clipboard_format_type_aura.cc" ] } - - sources += [ "clipboard_format_type.h" ] } defines = [ "IS_UI_BASE_CLIPBOARD_TYPES_IMPL" ] @@ -50,11 +51,11 @@ jumbo_component("clipboard_types") { deps = [ "//base" ] libs = [] + if (is_mac || is_ios) { + libs += [ "Foundation.framework" ] + } if (is_mac) { - libs += [ - "AppKit.framework", - "CoreFoundation.framework", - ] + libs += [ "AppKit.framework" ] } } @@ -64,6 +65,8 @@ jumbo_component("clipboard") { sources = [ "clipboard.cc", "clipboard.h", + "clipboard_metrics.cc", + "clipboard_metrics.h", "clipboard_monitor.cc", "clipboard_monitor.h", "clipboard_observer.h", @@ -112,16 +115,17 @@ jumbo_component("clipboard") { public_deps = [ ":clipboard_types" ] if (use_aura) { - # Aura clipboard. - # Chromecast uses clipboard_aura now. + # Linux clipboard implementations. if (is_desktop_linux && !is_chromecast) { + sources += [ "clipboard_linux.cc" ] if (use_ozone) { sources += [ "clipboard_ozone.cc", "clipboard_ozone.h", ] deps += [ "//ui/base" ] - } else if (use_x11) { + } + if (use_x11) { sources += [ "clipboard_x11.cc", "clipboard_x11.h", @@ -136,20 +140,20 @@ jumbo_component("clipboard") { ] } } else if (is_chromeos && ozone_platform_x11) { - # linux-chromeos uses aura clipboard by default, but supports ozone x11 - # with flag --use-system-clipbboard. + # linux-chromeos uses non-backed clipboard by default, but supports ozone + # x11 with flag --use-system-clipbboard. sources += [ - "clipboard_aura.cc", - "clipboard_aura.h", + "clipboard_non_backed.cc", + "clipboard_non_backed.h", "clipboard_ozone.cc", "clipboard_ozone.h", ] deps += [ "//ui/base" ] } else if (!is_win) { - # This file is used for all non-X11, non-Windows aura Builds. + # This file is used for all builds not backed by an underlying platform. sources += [ - "clipboard_aura.cc", - "clipboard_aura.h", + "clipboard_non_backed.cc", + "clipboard_non_backed.h", ] } } @@ -181,10 +185,10 @@ jumbo_source_set("clipboard_test_support") { "test/test_clipboard.cc", "test/test_clipboard.h", ] + } - if (is_android) { - sources += [ "clipboard_android_test_support.cc" ] - } + if (is_android) { + sources += [ "clipboard_android_test_support.cc" ] } public_deps = [ @@ -206,17 +210,17 @@ source_set("clipboard_test") { sources = [] output_name = "ui_base_clipboard_test" - if (is_mac) { + if (!is_ios) { sources += [ - "clipboard_mac_unittest.mm", - "clipboard_util_mac_unittest.mm", + "custom_data_helper_unittest.cc", + "test/test_clipboard_unittest.cc", ] } - if (!is_ios) { + if (is_mac) { sources += [ - "custom_data_helper_unittest.cc", - "test/test_clipboard_unittest.cc", + "clipboard_mac_unittest.mm", + "clipboard_util_mac_unittest.mm", ] } diff --git a/chromium/ui/base/clipboard/clipboard.cc b/chromium/ui/base/clipboard/clipboard.cc index a91de7c9517..a7722e261c1 100644 --- a/chromium/ui/base/clipboard/clipboard.cc +++ b/chromium/ui/base/clipboard/clipboard.cc @@ -203,4 +203,10 @@ base::Lock& Clipboard::ClipboardMapLock() { return *clipboard_map_lock; } +bool Clipboard::IsMarkedByOriginatorAsConfidential() const { + return false; +} + +void Clipboard::MarkAsConfidential() {} + } // namespace ui diff --git a/chromium/ui/base/clipboard/clipboard.h b/chromium/ui/base/clipboard/clipboard.h index 40f0e4d5e0d..1a69e8420d8 100644 --- a/chromium/ui/base/clipboard/clipboard.h +++ b/chromium/ui/base/clipboard/clipboard.h @@ -110,6 +110,17 @@ class COMPONENT_EXPORT(UI_BASE_CLIPBOARD) Clipboard virtual bool IsFormatAvailable(const ClipboardFormatType& format, ClipboardBuffer buffer) const = 0; + // Returns whether the clipboard has data that is marked by its originator as + // confidential. This is available for opt-in checking by the user of this API + // as confidential information, like passwords, might legitimately need to be + // manipulated. + virtual bool IsMarkedByOriginatorAsConfidential() const; + + // Mark the data on the clipboard as being confidential. This isn't + // implemented for all platforms yet, but this call should be made on every + // platform so that when it is implemented on other platforms it is picked up. + virtual void MarkAsConfidential(); + // Clear the clipboard data. virtual void Clear(ClipboardBuffer buffer) = 0; diff --git a/chromium/ui/base/clipboard/clipboard_android.cc b/chromium/ui/base/clipboard/clipboard_android.cc index 501d191e961..917d0d9d135 100644 --- a/chromium/ui/base/clipboard/clipboard_android.cc +++ b/chromium/ui/base/clipboard/clipboard_android.cc @@ -21,10 +21,12 @@ #include "base/strings/utf_string_conversions.h" #include "base/synchronization/lock.h" #include "base/task/post_task.h" +#include "base/task/thread_pool.h" #include "base/thread_annotations.h" #include "base/time/time.h" #include "third_party/skia/include/core/SkBitmap.h" #include "ui/base/clipboard/clipboard_constants.h" +#include "ui/base/clipboard/clipboard_metrics.h" #include "ui/base/ui_base_jni_headers/Clipboard_jni.h" #include "ui/gfx/android/java_bitmap.h" #include "ui/gfx/image/image.h" @@ -149,9 +151,8 @@ std::string ClipboardMap::Get(const std::string& format) { } void ClipboardMap::GetImage(ReadImageCallback callback) { - base::PostTaskAndReplyWithResult( - FROM_HERE, - {base::ThreadPool(), base::MayBlock(), base::TaskPriority::USER_BLOCKING}, + base::ThreadPool::PostTaskAndReplyWithResult( + FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_BLOCKING}, base::BindOnce(&GetImageData, clipboard_manager_), std::move(callback)); } @@ -432,6 +433,7 @@ void ClipboardAndroid::ReadAsciiText(ClipboardBuffer buffer, std::string* result) const { DCHECK(CalledOnValidThread()); DCHECK_EQ(buffer, ClipboardBuffer::kCopyPaste); + RecordRead(ClipboardFormatMetric::kText); *result = g_map.Get().Get(ClipboardFormatType::GetPlainTextType().GetName()); } @@ -443,6 +445,7 @@ void ClipboardAndroid::ReadHTML(ClipboardBuffer buffer, uint32_t* fragment_end) const { DCHECK(CalledOnValidThread()); DCHECK_EQ(buffer, ClipboardBuffer::kCopyPaste); + RecordRead(ClipboardFormatMetric::kHtml); if (src_url) src_url->clear(); @@ -464,6 +467,7 @@ void ClipboardAndroid::ReadImage(ClipboardBuffer buffer, ReadImageCallback callback) const { DCHECK(CalledOnValidThread()); DCHECK_EQ(buffer, ClipboardBuffer::kCopyPaste); + RecordRead(ClipboardFormatMetric::kImage); g_map.Get().GetImage(std::move(callback)); } @@ -483,6 +487,7 @@ void ClipboardAndroid::ReadBookmark(base::string16* title, void ClipboardAndroid::ReadData(const ClipboardFormatType& format, std::string* result) const { DCHECK(CalledOnValidThread()); + RecordRead(ClipboardFormatMetric::kData); *result = g_map.Get().Get(format.GetName()); } diff --git a/chromium/ui/base/clipboard/clipboard_constants.h b/chromium/ui/base/clipboard/clipboard_constants.h index 52048077f19..f57524d56b6 100644 --- a/chromium/ui/base/clipboard/clipboard_constants.h +++ b/chromium/ui/base/clipboard/clipboard_constants.h @@ -44,13 +44,20 @@ extern const char kMimeTypePepperCustomData[]; // Pickled data. COMPONENT_EXPORT(UI_BASE_CLIPBOARD_TYPES) extern NSString* const kWebCustomDataPboardType; + // Tells us if WebKit was the last to write to the pasteboard. There's no // actual data associated with this type. COMPONENT_EXPORT(UI_BASE_CLIPBOARD_TYPES) extern NSString* const kWebSmartPastePboardType; + // Pepper custom data format type. COMPONENT_EXPORT(UI_BASE_CLIPBOARD_TYPES) extern NSString* const kPepperCustomDataPboardType; + +// Data format used to tag the current data as confidential. +COMPONENT_EXPORT(UI_BASE_CLIPBOARD_TYPES) +extern NSString* const kUTTypeConfidentialData; + #endif // defined(OS_MACOSX) #if defined(OS_ANDROID) diff --git a/chromium/ui/base/clipboard/clipboard_constants_mac.mm b/chromium/ui/base/clipboard/clipboard_constants_mac.mm index 4f3029f6200..8633a201234 100644 --- a/chromium/ui/base/clipboard/clipboard_constants_mac.mm +++ b/chromium/ui/base/clipboard/clipboard_constants_mac.mm @@ -14,4 +14,9 @@ NSString* const kWebSmartPastePboardType = @"NeXT smart paste pasteboard type"; NSString* const kPepperCustomDataPboardType = @"org.chromium.pepper-custom-data"; +// It is the common convention on the Mac and on iOS that password managers tag +// confidential data with the flavor "org.nspasteboard.ConcealedType". Obey this +// convention. See http://nspasteboard.org/ for more info. +NSString* const kUTTypeConfidentialData = @"org.nspasteboard.ConcealedType"; + } // namespace ui diff --git a/chromium/ui/base/clipboard/clipboard_linux.cc b/chromium/ui/base/clipboard/clipboard_linux.cc new file mode 100644 index 00000000000..ef42052ed5d --- /dev/null +++ b/chromium/ui/base/clipboard/clipboard_linux.cc @@ -0,0 +1,33 @@ +// Copyright 2020 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.h" + +#if defined(USE_OZONE) +#include "ui/base/clipboard/clipboard_ozone.h" +#include "ui/base/ui_base_features.h" +#endif + +#if defined(USE_X11) +#include "ui/base/clipboard/clipboard_x11.h" +#endif + +namespace ui { + +// Clipboard factory method. +Clipboard* Clipboard::Create() { +#if defined(USE_OZONE) + if (features::IsUsingOzonePlatform()) + return new ClipboardOzone(); +#endif + +#if defined(USE_X11) + return new ClipboardX11(); +#else + NOTREACHED(); + return nullptr; +#endif +} + +} // namespace ui diff --git a/chromium/ui/base/clipboard/clipboard_mac.h b/chromium/ui/base/clipboard/clipboard_mac.h index 9ebd21cd157..507a7f8c786 100644 --- a/chromium/ui/base/clipboard/clipboard_mac.h +++ b/chromium/ui/base/clipboard/clipboard_mac.h @@ -33,6 +33,8 @@ class COMPONENT_EXPORT(UI_BASE_CLIPBOARD) ClipboardMac : public Clipboard { uint64_t GetSequenceNumber(ClipboardBuffer buffer) const override; bool IsFormatAvailable(const ClipboardFormatType& format, ClipboardBuffer buffer) const override; + bool IsMarkedByOriginatorAsConfidential() const override; + void MarkAsConfidential() override; void Clear(ClipboardBuffer buffer) override; void ReadAvailableTypes(ClipboardBuffer buffer, std::vector<base::string16>* types) const override; diff --git a/chromium/ui/base/clipboard/clipboard_mac.mm b/chromium/ui/base/clipboard/clipboard_mac.mm index 4c8e0e874b0..c396f9effea 100644 --- a/chromium/ui/base/clipboard/clipboard_mac.mm +++ b/chromium/ui/base/clipboard/clipboard_mac.mm @@ -24,6 +24,7 @@ #import "third_party/mozilla/NSPasteboard+Utils.h" #include "third_party/skia/include/core/SkBitmap.h" #include "ui/base/clipboard/clipboard_constants.h" +#include "ui/base/clipboard/clipboard_metrics.h" #include "ui/base/clipboard/clipboard_util_mac.h" #include "ui/base/clipboard/custom_data_helper.h" #include "ui/gfx/canvas.h" @@ -85,6 +86,27 @@ bool ClipboardMac::IsFormatAvailable(const ClipboardFormatType& format, return [types containsObject:format.ToNSString()]; } +bool ClipboardMac::IsMarkedByOriginatorAsConfidential() const { + DCHECK(CalledOnValidThread()); + + NSPasteboard* pb = GetPasteboard(); + NSPasteboardType type = + [pb availableTypeFromArray:@[ kUTTypeConfidentialData ]]; + + if (type) + return true; + + return false; +} + +void ClipboardMac::MarkAsConfidential() { + DCHECK(CalledOnValidThread()); + + NSPasteboard* pb = GetPasteboard(); + [pb addTypes:@[ kUTTypeConfidentialData ] owner:nil]; + [pb setData:nil forType:kUTTypeConfidentialData]; +} + void ClipboardMac::Clear(ClipboardBuffer buffer) { DCHECK(CalledOnValidThread()); DCHECK_EQ(buffer, ClipboardBuffer::kCopyPaste); @@ -138,6 +160,7 @@ void ClipboardMac::ReadText(ClipboardBuffer buffer, base::string16* result) const { DCHECK(CalledOnValidThread()); DCHECK_EQ(buffer, ClipboardBuffer::kCopyPaste); + RecordRead(ClipboardFormatMetric::kText); NSPasteboard* pb = GetPasteboard(); NSString* contents = [pb stringForType:NSPasteboardTypeString]; @@ -148,6 +171,7 @@ void ClipboardMac::ReadAsciiText(ClipboardBuffer buffer, std::string* result) const { DCHECK(CalledOnValidThread()); DCHECK_EQ(buffer, ClipboardBuffer::kCopyPaste); + RecordRead(ClipboardFormatMetric::kText); NSPasteboard* pb = GetPasteboard(); NSString* contents = [pb stringForType:NSPasteboardTypeString]; @@ -164,6 +188,7 @@ void ClipboardMac::ReadHTML(ClipboardBuffer buffer, uint32_t* fragment_end) const { DCHECK(CalledOnValidThread()); DCHECK_EQ(buffer, ClipboardBuffer::kCopyPaste); + RecordRead(ClipboardFormatMetric::kHtml); // TODO(avi): src_url? markup->clear(); @@ -191,12 +216,14 @@ void ClipboardMac::ReadHTML(ClipboardBuffer buffer, void ClipboardMac::ReadRTF(ClipboardBuffer buffer, std::string* result) const { DCHECK(CalledOnValidThread()); DCHECK_EQ(buffer, ClipboardBuffer::kCopyPaste); + RecordRead(ClipboardFormatMetric::kRtf); return ReadData(ClipboardFormatType::GetRtfType(), result); } void ClipboardMac::ReadImage(ClipboardBuffer buffer, ReadImageCallback callback) const { + RecordRead(ClipboardFormatMetric::kImage); std::move(callback).Run(ReadImageInternal(buffer, GetPasteboard())); } @@ -205,6 +232,7 @@ void ClipboardMac::ReadCustomData(ClipboardBuffer buffer, base::string16* result) const { DCHECK(CalledOnValidThread()); DCHECK_EQ(buffer, ClipboardBuffer::kCopyPaste); + RecordRead(ClipboardFormatMetric::kCustomData); NSPasteboard* pb = GetPasteboard(); if ([[pb types] containsObject:kWebCustomDataPboardType]) { @@ -216,6 +244,7 @@ void ClipboardMac::ReadCustomData(ClipboardBuffer buffer, void ClipboardMac::ReadBookmark(base::string16* title, std::string* url) const { DCHECK(CalledOnValidThread()); + RecordRead(ClipboardFormatMetric::kBookmark); NSPasteboard* pb = GetPasteboard(); if (title) { @@ -235,6 +264,7 @@ void ClipboardMac::ReadBookmark(base::string16* title, std::string* url) const { void ClipboardMac::ReadData(const ClipboardFormatType& format, std::string* result) const { DCHECK(CalledOnValidThread()); + RecordRead(ClipboardFormatMetric::kData); NSPasteboard* pb = GetPasteboard(); NSData* data = [pb dataForType:format.ToNSString()]; if ([data length]) diff --git a/chromium/ui/base/clipboard/clipboard_metrics.cc b/chromium/ui/base/clipboard/clipboard_metrics.cc new file mode 100644 index 00000000000..dc52ad67926 --- /dev/null +++ b/chromium/ui/base/clipboard/clipboard_metrics.cc @@ -0,0 +1,20 @@ +// Copyright 2020 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_metrics.h" + +#include "base/metrics/histogram_functions.h" +#include "base/metrics/histogram_macros.h" + +namespace ui { + +void RecordRead(ClipboardFormatMetric metric) { + base::UmaHistogramEnumeration("Clipboard.Read", metric); +} + +void RecordWrite(ClipboardFormatMetric metric) { + base::UmaHistogramEnumeration("Clipboard.Write", metric); +} + +} // namespace ui diff --git a/chromium/ui/base/clipboard/clipboard_metrics.h b/chromium/ui/base/clipboard/clipboard_metrics.h new file mode 100644 index 00000000000..5077043bafe --- /dev/null +++ b/chromium/ui/base/clipboard/clipboard_metrics.h @@ -0,0 +1,30 @@ +// Copyright 2020 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_METRICS_H_ +#define UI_BASE_CLIPBOARD_CLIPBOARD_METRICS_H_ + +namespace ui { + +// Used to log formats read/written from/to the platform clipboard. +// +// This enum's values are persisted to logs. Do not reuse or renumber values. +enum class ClipboardFormatMetric { + kText = 0, // On applicable platforms, includes both UNICODE and ANSI text. + kHtml = 1, + kRtf = 2, + kImage = 3, + kBookmark = 4, + kData = 5, + kCustomData = 6, + kWebSmartPaste = 7, // Only used on write. + kMaxValue = kWebSmartPaste, +}; + +void RecordRead(ClipboardFormatMetric metric); +void RecordWrite(ClipboardFormatMetric metric); + +} // namespace ui + +#endif // UI_BASE_CLIPBOARD_CLIPBOARD_MONITOR_H_ diff --git a/chromium/ui/base/clipboard/clipboard_aura.cc b/chromium/ui/base/clipboard/clipboard_non_backed.cc index 9f4ae70a5ed..2b827891f6d 100644 --- a/chromium/ui/base/clipboard/clipboard_aura.cc +++ b/chromium/ui/base/clipboard/clipboard_non_backed.cc @@ -2,7 +2,7 @@ // 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_aura.h" +#include "ui/base/clipboard/clipboard_non_backed.h" #include <stdint.h> @@ -22,6 +22,7 @@ #include "third_party/skia/include/core/SkBitmap.h" #include "ui/base/clipboard/clipboard_constants.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/gfx/geometry/size.h" @@ -33,8 +34,8 @@ namespace { const size_t kMaxClipboardSize = 1; -// Clipboard data format used by AuraClipboard. -enum class AuraClipboardFormat { +// Clipboard data format used by ClipboardInternal. +enum class ClipboardInternalFormat { kText = 1 << 0, kHtml = 1 << 1, kRtf = 1 << 2, @@ -48,49 +49,47 @@ enum class AuraClipboardFormat { // It mostly just provides APIs to cleanly access and manipulate this data. class ClipboardData { public: - ClipboardData() - : web_smart_paste_(false), - format_(0) {} + ClipboardData() : web_smart_paste_(false), format_(0) {} virtual ~ClipboardData() = default; - // Bitmask of AuraClipboardFormat types. + // Bitmask of ClipboardInternalFormat types. int format() const { return format_; } const std::string& text() const { return text_; } void set_text(const std::string& text) { text_ = text; - format_ |= static_cast<int>(AuraClipboardFormat::kText); + format_ |= static_cast<int>(ClipboardInternalFormat::kText); } const std::string& markup_data() const { return markup_data_; } void set_markup_data(const std::string& markup_data) { markup_data_ = markup_data; - format_ |= static_cast<int>(AuraClipboardFormat::kHtml); + format_ |= static_cast<int>(ClipboardInternalFormat::kHtml); } const std::string& rtf_data() const { return rtf_data_; } void SetRTFData(const std::string& rtf_data) { rtf_data_ = rtf_data; - format_ |= static_cast<int>(AuraClipboardFormat::kRtf); + format_ |= static_cast<int>(ClipboardInternalFormat::kRtf); } const std::string& url() const { return url_; } void set_url(const std::string& url) { url_ = url; - format_ |= static_cast<int>(AuraClipboardFormat::kHtml); + format_ |= static_cast<int>(ClipboardInternalFormat::kHtml); } const std::string& bookmark_title() const { return bookmark_title_; } void set_bookmark_title(const std::string& bookmark_title) { bookmark_title_ = bookmark_title; - format_ |= static_cast<int>(AuraClipboardFormat::kBookmark); + format_ |= static_cast<int>(ClipboardInternalFormat::kBookmark); } const std::string& bookmark_url() const { return bookmark_url_; } void set_bookmark_url(const std::string& bookmark_url) { bookmark_url_ = bookmark_url; - format_ |= static_cast<int>(AuraClipboardFormat::kBookmark); + format_ |= static_cast<int>(ClipboardInternalFormat::kBookmark); } const SkBitmap& bitmap() const { return bitmap_; } @@ -99,7 +98,7 @@ class ClipboardData { NOTREACHED() << "Unable to convert bitmap for clipboard"; return; } - format_ |= static_cast<int>(AuraClipboardFormat::kBitmap); + format_ |= static_cast<int>(ClipboardInternalFormat::kBitmap); } const std::string& custom_data_format() const { return custom_data_format_; } @@ -113,13 +112,13 @@ class ClipboardData { } custom_data_data_ = data_data; custom_data_format_ = data_format; - format_ |= static_cast<int>(AuraClipboardFormat::kCustom); + format_ |= static_cast<int>(ClipboardInternalFormat::kCustom); } bool web_smart_paste() const { return web_smart_paste_; } void set_web_smart_paste(bool web_smart_paste) { web_smart_paste_ = web_smart_paste; - format_ |= static_cast<int>(AuraClipboardFormat::kWeb); + format_ |= static_cast<int>(ClipboardInternalFormat::kWeb); } private: @@ -157,16 +156,13 @@ class ClipboardData { } // namespace -// Platform clipboard implementation for Aura. This handles things like format -// conversion, versioning of clipboard items etc. The goal is to roughly provide -// a substitute to platform clipboards on other platforms such as GtkClipboard -// on gtk or winapi clipboard on win. -class AuraClipboard { +// Simple, internal implementation of a clipboard, handling things like format +// conversion, versioning, etc. +class ClipboardInternal { public: - AuraClipboard() : sequence_number_(0) { - } + ClipboardInternal() : sequence_number_(0) {} - ~AuraClipboard() = default; + ~ClipboardInternal() = default; void Clear() { sequence_number_++; @@ -174,9 +170,7 @@ class AuraClipboard { ClipboardMonitor::GetInstance()->NotifyClipboardDataChanged(); } - uint64_t sequence_number() const { - return sequence_number_; - } + uint64_t sequence_number() const { return sequence_number_; } // Returns the data currently on the top of the clipboard stack, nullptr if // the clipboard stack is empty. @@ -188,11 +182,11 @@ class AuraClipboard { // 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(AuraClipboardFormat format) const { + bool IsFormatAvailable(ClipboardInternalFormat format) const { switch (format) { - case AuraClipboardFormat::kText: - return HasFormat(AuraClipboardFormat::kText) || - HasFormat(AuraClipboardFormat::kBookmark); + case ClipboardInternalFormat::kText: + return HasFormat(ClipboardInternalFormat::kText) || + HasFormat(ClipboardInternalFormat::kBookmark); default: return HasFormat(format); } @@ -211,11 +205,11 @@ class AuraClipboard { const ClipboardData* data = GetData(); if (!data) return; - if (HasFormat(AuraClipboardFormat::kText)) + if (HasFormat(ClipboardInternalFormat::kText)) *result = data->text(); - else if (HasFormat(AuraClipboardFormat::kHtml)) + else if (HasFormat(ClipboardInternalFormat::kHtml)) *result = data->markup_data(); - else if (HasFormat(AuraClipboardFormat::kBookmark)) + else if (HasFormat(ClipboardInternalFormat::kBookmark)) *result = data->bookmark_url(); } @@ -230,7 +224,7 @@ class AuraClipboard { *fragment_start = 0; *fragment_end = 0; - if (!HasFormat(AuraClipboardFormat::kHtml)) + if (!HasFormat(ClipboardInternalFormat::kHtml)) return; const ClipboardData* data = GetData(); @@ -246,7 +240,7 @@ class AuraClipboard { void ReadRTF(std::string* result) const { result->clear(); const ClipboardData* data = GetData(); - if (!HasFormat(AuraClipboardFormat::kRtf)) + if (!HasFormat(ClipboardInternalFormat::kRtf)) return; *result = data->rtf_data(); @@ -255,7 +249,7 @@ class AuraClipboard { // Reads image from the data at the top of clipboard stack. SkBitmap ReadImage() const { SkBitmap img; - if (!HasFormat(AuraClipboardFormat::kBitmap)) + if (!HasFormat(ClipboardInternalFormat::kBitmap)) return img; // A shallow copy should be fine here, but just to be safe... @@ -272,7 +266,7 @@ class AuraClipboard { base::string16* result) const { result->clear(); const ClipboardData* data = GetData(); - if (!HasFormat(AuraClipboardFormat::kCustom)) + if (!HasFormat(ClipboardInternalFormat::kCustom)) return; ReadCustomDataForType(data->custom_data_data().c_str(), @@ -285,7 +279,7 @@ class AuraClipboard { title->clear(); if (url) url->clear(); - if (!HasFormat(AuraClipboardFormat::kBookmark)) + if (!HasFormat(ClipboardInternalFormat::kBookmark)) return; const ClipboardData* data = GetData(); @@ -298,7 +292,7 @@ class AuraClipboard { void ReadData(const std::string& type, std::string* result) const { result->clear(); const ClipboardData* data = GetData(); - if (!HasFormat(AuraClipboardFormat::kCustom) || + if (!HasFormat(ClipboardInternalFormat::kCustom) || type != data->custom_data_format()) return; @@ -314,7 +308,7 @@ class AuraClipboard { private: // True if the data on top of the clipboard stack has format |format|. - bool HasFormat(AuraClipboardFormat format) const { + bool HasFormat(ClipboardInternalFormat format) const { const ClipboardData* data = GetData(); return data ? data->format() & static_cast<int>(format) : false; } @@ -337,13 +331,13 @@ class AuraClipboard { // Sequence number uniquely identifying clipboard state. uint64_t sequence_number_; - DISALLOW_COPY_AND_ASSIGN(AuraClipboard); + DISALLOW_COPY_AND_ASSIGN(ClipboardInternal); }; // Helper class to build a ClipboardData object and write it to clipboard. class ClipboardDataBuilder { public: - static void CommitToClipboard(AuraClipboard* clipboard) { + static void CommitToClipboard(ClipboardInternal* clipboard) { clipboard->WriteData(TakeCurrentData()); } @@ -411,58 +405,63 @@ class ClipboardDataBuilder { ClipboardData* ClipboardDataBuilder::current_data_ = nullptr; -// linux-chromeos uses aura clipboard by default, but supports ozone x11 +// linux-chromeos uses non-backed clipboard by default, but supports ozone x11 // with flag --use-system-clipbboard. #if !defined(OS_CHROMEOS) || !BUILDFLAG(OZONE_PLATFORM_X11) // Clipboard factory method. Clipboard* Clipboard::Create() { - return new ClipboardAura; + return new ClipboardNonBacked; } #endif -// ClipboardAura implementation. -ClipboardAura::ClipboardAura() - : clipboard_internal_(std::make_unique<AuraClipboard>()) { +// ClipboardNonBacked implementation. +ClipboardNonBacked::ClipboardNonBacked() + : clipboard_internal_(std::make_unique<ClipboardInternal>()) { DCHECK(CalledOnValidThread()); } -ClipboardAura::~ClipboardAura() { +ClipboardNonBacked::~ClipboardNonBacked() { DCHECK(CalledOnValidThread()); } -void ClipboardAura::OnPreShutdown() {} +void ClipboardNonBacked::OnPreShutdown() {} -uint64_t ClipboardAura::GetSequenceNumber(ClipboardBuffer buffer) const { +uint64_t ClipboardNonBacked::GetSequenceNumber(ClipboardBuffer buffer) const { DCHECK(CalledOnValidThread()); return clipboard_internal_->sequence_number(); } -bool ClipboardAura::IsFormatAvailable(const ClipboardFormatType& format, - ClipboardBuffer buffer) const { +bool ClipboardNonBacked::IsFormatAvailable(const ClipboardFormatType& format, + ClipboardBuffer buffer) const { DCHECK(CalledOnValidThread()); DCHECK(IsSupportedClipboardBuffer(buffer)); if (ClipboardFormatType::GetPlainTextType().Equals(format) || ClipboardFormatType::GetUrlType().Equals(format)) - return clipboard_internal_->IsFormatAvailable(AuraClipboardFormat::kText); + return clipboard_internal_->IsFormatAvailable( + ClipboardInternalFormat::kText); if (ClipboardFormatType::GetHtmlType().Equals(format)) - return clipboard_internal_->IsFormatAvailable(AuraClipboardFormat::kHtml); + return clipboard_internal_->IsFormatAvailable( + ClipboardInternalFormat::kHtml); if (ClipboardFormatType::GetRtfType().Equals(format)) - return clipboard_internal_->IsFormatAvailable(AuraClipboardFormat::kRtf); + return clipboard_internal_->IsFormatAvailable( + ClipboardInternalFormat::kRtf); if (ClipboardFormatType::GetBitmapType().Equals(format)) - return clipboard_internal_->IsFormatAvailable(AuraClipboardFormat::kBitmap); + return clipboard_internal_->IsFormatAvailable( + ClipboardInternalFormat::kBitmap); if (ClipboardFormatType::GetWebKitSmartPasteType().Equals(format)) - return clipboard_internal_->IsFormatAvailable(AuraClipboardFormat::kWeb); + return clipboard_internal_->IsFormatAvailable( + ClipboardInternalFormat::kWeb); const ClipboardData* data = clipboard_internal_->GetData(); return data && data->custom_data_format() == format.GetName(); } -void ClipboardAura::Clear(ClipboardBuffer buffer) { +void ClipboardNonBacked::Clear(ClipboardBuffer buffer) { DCHECK(CalledOnValidThread()); DCHECK(IsSupportedClipboardBuffer(buffer)); clipboard_internal_->Clear(); } -void ClipboardAura::ReadAvailableTypes( +void ClipboardNonBacked::ReadAvailableTypes( ClipboardBuffer buffer, std::vector<base::string16>* types) const { DCHECK(CalledOnValidThread()); @@ -481,7 +480,8 @@ void ClipboardAura::ReadAvailableTypes( if (IsFormatAvailable(ClipboardFormatType::GetBitmapType(), buffer)) types->push_back(base::UTF8ToUTF16(kMimeTypePNG)); - if (clipboard_internal_->IsFormatAvailable(AuraClipboardFormat::kCustom) && + if (clipboard_internal_->IsFormatAvailable( + ClipboardInternalFormat::kCustom) && clipboard_internal_->GetData()) { ReadCustomDataTypes( clipboard_internal_->GetData()->custom_data_data().c_str(), @@ -490,7 +490,7 @@ void ClipboardAura::ReadAvailableTypes( } std::vector<base::string16> -ClipboardAura::ReadAvailablePlatformSpecificFormatNames( +ClipboardNonBacked::ReadAvailablePlatformSpecificFormatNames( ClipboardBuffer buffer) const { DCHECK(CalledOnValidThread()); @@ -516,59 +516,69 @@ ClipboardAura::ReadAvailablePlatformSpecificFormatNames( return types; } -void ClipboardAura::ReadText(ClipboardBuffer buffer, - base::string16* result) const { +void ClipboardNonBacked::ReadText(ClipboardBuffer buffer, + base::string16* result) const { DCHECK(CalledOnValidThread()); + RecordRead(ClipboardFormatMetric::kText); clipboard_internal_->ReadText(result); } -void ClipboardAura::ReadAsciiText(ClipboardBuffer buffer, - std::string* result) const { +void ClipboardNonBacked::ReadAsciiText(ClipboardBuffer buffer, + std::string* result) const { DCHECK(CalledOnValidThread()); + RecordRead(ClipboardFormatMetric::kText); clipboard_internal_->ReadAsciiText(result); } -void ClipboardAura::ReadHTML(ClipboardBuffer buffer, - base::string16* markup, - std::string* src_url, - uint32_t* fragment_start, - uint32_t* fragment_end) const { +void ClipboardNonBacked::ReadHTML(ClipboardBuffer buffer, + base::string16* markup, + std::string* src_url, + uint32_t* fragment_start, + uint32_t* fragment_end) const { DCHECK(CalledOnValidThread()); + RecordRead(ClipboardFormatMetric::kHtml); clipboard_internal_->ReadHTML(markup, src_url, fragment_start, fragment_end); } -void ClipboardAura::ReadRTF(ClipboardBuffer buffer, std::string* result) const { +void ClipboardNonBacked::ReadRTF(ClipboardBuffer buffer, + std::string* result) const { DCHECK(CalledOnValidThread()); + RecordRead(ClipboardFormatMetric::kRtf); clipboard_internal_->ReadRTF(result); } -void ClipboardAura::ReadImage(ClipboardBuffer buffer, - ReadImageCallback callback) const { +void ClipboardNonBacked::ReadImage(ClipboardBuffer buffer, + ReadImageCallback callback) const { DCHECK(CalledOnValidThread()); + RecordRead(ClipboardFormatMetric::kImage); std::move(callback).Run(clipboard_internal_->ReadImage()); } -void ClipboardAura::ReadCustomData(ClipboardBuffer buffer, - const base::string16& type, - base::string16* result) const { +void ClipboardNonBacked::ReadCustomData(ClipboardBuffer buffer, + const base::string16& type, + base::string16* result) const { DCHECK(CalledOnValidThread()); + RecordRead(ClipboardFormatMetric::kCustomData); clipboard_internal_->ReadCustomData(type, result); } -void ClipboardAura::ReadBookmark(base::string16* title, - std::string* url) const { +void ClipboardNonBacked::ReadBookmark(base::string16* title, + std::string* url) const { DCHECK(CalledOnValidThread()); + RecordRead(ClipboardFormatMetric::kBookmark); clipboard_internal_->ReadBookmark(title, url); } -void ClipboardAura::ReadData(const ClipboardFormatType& format, - std::string* result) const { +void ClipboardNonBacked::ReadData(const ClipboardFormatType& format, + std::string* result) const { DCHECK(CalledOnValidThread()); + RecordRead(ClipboardFormatMetric::kData); clipboard_internal_->ReadData(format.GetName(), result); } -void ClipboardAura::WritePortableRepresentations(ClipboardBuffer buffer, - const ObjectMap& objects) { +void ClipboardNonBacked::WritePortableRepresentations( + ClipboardBuffer buffer, + const ObjectMap& objects) { DCHECK(CalledOnValidThread()); DCHECK(IsSupportedClipboardBuffer(buffer)); for (const auto& object : objects) @@ -576,7 +586,7 @@ void ClipboardAura::WritePortableRepresentations(ClipboardBuffer buffer, ClipboardDataBuilder::CommitToClipboard(clipboard_internal_.get()); } -void ClipboardAura::WritePlatformRepresentations( +void ClipboardNonBacked::WritePlatformRepresentations( ClipboardBuffer buffer, std::vector<Clipboard::PlatformRepresentation> platform_representations) { DCHECK(CalledOnValidThread()); @@ -587,39 +597,39 @@ void ClipboardAura::WritePlatformRepresentations( ClipboardDataBuilder::CommitToClipboard(clipboard_internal_.get()); } -void ClipboardAura::WriteText(const char* text_data, size_t text_len) { +void ClipboardNonBacked::WriteText(const char* text_data, size_t text_len) { ClipboardDataBuilder::WriteText(text_data, text_len); } -void ClipboardAura::WriteHTML(const char* markup_data, - size_t markup_len, - const char* url_data, - size_t url_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 ClipboardAura::WriteRTF(const char* rtf_data, size_t data_len) { +void ClipboardNonBacked::WriteRTF(const char* rtf_data, size_t data_len) { ClipboardDataBuilder::WriteRTF(rtf_data, data_len); } -void ClipboardAura::WriteBookmark(const char* title_data, - size_t title_len, - const char* url_data, - size_t url_len) { +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 ClipboardAura::WriteWebSmartPaste() { +void ClipboardNonBacked::WriteWebSmartPaste() { ClipboardDataBuilder::WriteWebSmartPaste(); } -void ClipboardAura::WriteBitmap(const SkBitmap& bitmap) { +void ClipboardNonBacked::WriteBitmap(const SkBitmap& bitmap) { ClipboardDataBuilder::WriteBitmap(bitmap); } -void ClipboardAura::WriteData(const ClipboardFormatType& format, - const char* data_data, - size_t data_len) { +void ClipboardNonBacked::WriteData(const ClipboardFormatType& format, + const char* data_data, + size_t data_len) { ClipboardDataBuilder::WriteData(format.GetName(), data_data, data_len); } diff --git a/chromium/ui/base/clipboard/clipboard_aura.h b/chromium/ui/base/clipboard/clipboard_non_backed.h index 6a6862ba688..8f57aca1e25 100644 --- a/chromium/ui/base/clipboard/clipboard_aura.h +++ b/chromium/ui/base/clipboard/clipboard_non_backed.h @@ -2,8 +2,8 @@ // 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_AURA_H_ -#define UI_BASE_CLIPBOARD_CLIPBOARD_AURA_H_ +#ifndef UI_BASE_CLIPBOARD_CLIPBOARD_NON_BACKED_H_ +#define UI_BASE_CLIPBOARD_CLIPBOARD_NON_BACKED_H_ #include <stddef.h> #include <stdint.h> @@ -13,13 +13,19 @@ namespace ui { -class AuraClipboard; +class ClipboardInternal; -class ClipboardAura : public Clipboard { +// In-memory clipboard implementation not backed by an underlying platform. +// This clipboard can be used where there's no need to sync the clipboard with +// an underlying platform, and can substitute platform clipboards like +// ClipboardWin on Windows or ClipboardMac on MacOS. As this isn't backed by an +// underlying platform, the clipboard data isn't persisted after an instance +// goes away. +class ClipboardNonBacked : public Clipboard { private: friend class Clipboard; - ClipboardAura(); - ~ClipboardAura() override; + ClipboardNonBacked(); + ~ClipboardNonBacked() override; // Clipboard overrides: void OnPreShutdown() override; @@ -70,11 +76,11 @@ class ClipboardAura : public Clipboard { const char* data_data, size_t data_len) override; - const std::unique_ptr<AuraClipboard> clipboard_internal_; + const std::unique_ptr<ClipboardInternal> clipboard_internal_; - DISALLOW_COPY_AND_ASSIGN(ClipboardAura); + DISALLOW_COPY_AND_ASSIGN(ClipboardNonBacked); }; } // namespace ui -#endif // UI_BASE_CLIPBOARD_CLIPBOARD_AURA_H_ +#endif // UI_BASE_CLIPBOARD_CLIPBOARD_NON_BACKED_H_ diff --git a/chromium/ui/base/clipboard/clipboard_ozone.cc b/chromium/ui/base/clipboard/clipboard_ozone.cc index bb5b7ad7182..a41bc2f5798 100644 --- a/chromium/ui/base/clipboard/clipboard_ozone.cc +++ b/chromium/ui/base/clipboard/clipboard_ozone.cc @@ -15,9 +15,11 @@ #include "base/run_loop.h" #include "base/strings/utf_string_conversions.h" #include "base/timer/timer.h" +#include "build/build_config.h" #include "third_party/skia/include/core/SkBitmap.h" #include "ui/base/clipboard/clipboard_buffer.h" #include "ui/base/clipboard/clipboard_constants.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/gfx/codec/png_codec.h" @@ -27,7 +29,7 @@ #if defined(OS_CHROMEOS) && BUILDFLAG(OZONE_PLATFORM_X11) #include "base/command_line.h" -#include "ui/base/clipboard/clipboard_aura.h" +#include "ui/base/clipboard/clipboard_non_backed.h" #include "ui/base/ui_base_switches.h" #endif @@ -294,18 +296,21 @@ class ClipboardOzone::AsyncClipboardOzone { DISALLOW_COPY_AND_ASSIGN(AsyncClipboardOzone); }; +// Uses the factory in the clipboard_linux otherwise. +#if defined(OS_CHROMEOS) || !defined(OS_LINUX) // Clipboard factory method. Clipboard* Clipboard::Create() { -// linux-chromeos uses aura clipboard by default, but supports ozone x11 +// linux-chromeos uses non-backed clipboard by default, but supports ozone x11 // with flag --use-system-clipbboard. #if defined(OS_CHROMEOS) && BUILDFLAG(OZONE_PLATFORM_X11) if (!base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kUseSystemClipboard)) { - return new ClipboardAura; + return new ClipboardNonBacked; } #endif return new ClipboardOzone; } +#endif // ClipboardOzone implementation. ClipboardOzone::ClipboardOzone() { @@ -383,6 +388,7 @@ ClipboardOzone::ReadAvailablePlatformSpecificFormatNames( void ClipboardOzone::ReadText(ClipboardBuffer buffer, base::string16* result) const { DCHECK(CalledOnValidThread()); + RecordRead(ClipboardFormatMetric::kText); auto clipboard_data = async_clipboard_ozone_->ReadClipboardDataAndWait(buffer, kMimeTypeText); @@ -393,6 +399,7 @@ void ClipboardOzone::ReadText(ClipboardBuffer buffer, void ClipboardOzone::ReadAsciiText(ClipboardBuffer buffer, std::string* result) const { DCHECK(CalledOnValidThread()); + RecordRead(ClipboardFormatMetric::kText); auto clipboard_data = async_clipboard_ozone_->ReadClipboardDataAndWait(buffer, kMimeTypeText); @@ -405,6 +412,7 @@ void ClipboardOzone::ReadHTML(ClipboardBuffer buffer, uint32_t* fragment_start, uint32_t* fragment_end) const { DCHECK(CalledOnValidThread()); + RecordRead(ClipboardFormatMetric::kHtml); markup->clear(); if (src_url) @@ -423,6 +431,7 @@ void ClipboardOzone::ReadHTML(ClipboardBuffer buffer, void ClipboardOzone::ReadRTF(ClipboardBuffer buffer, std::string* result) const { DCHECK(CalledOnValidThread()); + RecordRead(ClipboardFormatMetric::kRtf); auto clipboard_data = async_clipboard_ozone_->ReadClipboardDataAndWait(buffer, kMimeTypeRTF); @@ -431,6 +440,7 @@ void ClipboardOzone::ReadRTF(ClipboardBuffer buffer, void ClipboardOzone::ReadImage(ClipboardBuffer buffer, ReadImageCallback callback) const { + RecordRead(ClipboardFormatMetric::kImage); std::move(callback).Run(ReadImageInternal(buffer)); } @@ -438,6 +448,7 @@ void ClipboardOzone::ReadCustomData(ClipboardBuffer buffer, const base::string16& type, base::string16* result) const { DCHECK(CalledOnValidThread()); + RecordRead(ClipboardFormatMetric::kCustomData); auto custom_data = async_clipboard_ozone_->ReadClipboardDataAndWait( buffer, kMimeTypeWebCustomData); @@ -454,6 +465,7 @@ void ClipboardOzone::ReadBookmark(base::string16* title, void ClipboardOzone::ReadData(const ClipboardFormatType& format, std::string* result) const { DCHECK(CalledOnValidThread()); + RecordRead(ClipboardFormatMetric::kData); auto clipboard_data = async_clipboard_ozone_->ReadClipboardDataAndWait( ClipboardBuffer::kCopyPaste, format.GetName()); @@ -469,8 +481,8 @@ void ClipboardOzone::WritePortableRepresentations(ClipboardBuffer buffer, async_clipboard_ozone_->OfferData(buffer); - // Just like Aura/X11 implementation does, copy text data from the copy/paste - // selection to the primary selection. + // Just like Non-Backed/X11 implementation does, copy text data from the + // copy/paste selection to the primary selection. if (buffer == ClipboardBuffer::kCopyPaste) { auto text_iter = objects.find(PortableFormat::kText); if (text_iter != objects.end()) { diff --git a/chromium/ui/base/clipboard/clipboard_test_template.h b/chromium/ui/base/clipboard/clipboard_test_template.h index f31c2594b7d..279252ce350 100644 --- a/chromium/ui/base/clipboard/clipboard_test_template.h +++ b/chromium/ui/base/clipboard/clipboard_test_template.h @@ -46,6 +46,7 @@ #endif #if defined(USE_X11) +#include "ui/base/ui_base_features.h" #include "ui/events/platform/platform_event_source.h" #endif @@ -67,7 +68,8 @@ class ClipboardTest : public PlatformTest { void SetUp() override { PlatformTest::SetUp(); #if defined(USE_X11) - event_source_ = ClipboardTraits::GetEventSource(); + if (!features::IsUsingOzonePlatform()) + event_source_ = ClipboardTraits::GetEventSource(); #endif clipboard_ = ClipboardTraits::Create(); } @@ -653,8 +655,8 @@ TYPED_TEST(ClipboardTest, DataTest) { } // TODO(https://crbug.com/1032161): Implement multiple raw types for -// AuraClipboard. This test currently doesn't run on AuraClipboard because -// AuraClipboard only supports one raw type. +// ClipboardInternal. This test currently doesn't run on ClipboardInternal +// because ClipboardInternal only supports one raw type. #if (!defined(USE_AURA) || defined(OS_WIN) || defined(USE_OZONE) || \ defined(USE_X11)) && \ !defined(OS_CHROMEOS) @@ -739,17 +741,38 @@ TYPED_TEST(ClipboardTest, ReadAvailablePlatformSpecificFormatNamesTest) { #endif } -// Test that a platform-specific write works. +// Test that platform-specific functionality works, with a predefined format in +// On X11 Linux, this test uses a simple MIME type, text/plain. +// On Windows, this test uses a pre-defined ANSI format, CF_TEXT, and tests that +// the Windows implicitly converts this to UNICODE as expected. +#if defined(OS_WIN) || defined(USE_X11) +TYPED_TEST(ClipboardTest, PlatformSpecificDataTest) { + // We're testing platform-specific behavior, so use PlatformClipboardTest. + // TODO(https://crbug.com/1083050): The template shouldn't know about its + // instantiations. Move this information up using a flag, virtual method, or + // creating separate test files for different platforms. + std::string test_suite_name = ::testing::UnitTest::GetInstance() + ->current_test_info() + ->test_suite_name(); + if (test_suite_name != std::string("ClipboardTest/PlatformClipboardTest")) + return; + + const std::string text = "test string"; #if defined(OS_WIN) -TYPED_TEST(ClipboardTest, WindowsPredefinedFormatWriteDataTest) { + // Windows pre-defined ANSI text format. const std::string kFormatString = "CF_TEXT"; - const std::string text = "test string"; + // Windows requires an extra '\0' at the end for a raw write. + const std::string kPlatformSpecificText = text + '\0'; +#elif defined(USE_X11) + const std::string kFormatString = "text/plain"; // X11 text format + const std::string kPlatformSpecificText = text; +#endif base::span<const uint8_t> text_span( - reinterpret_cast<const uint8_t*>(text.data()), text.size() + 1); - + reinterpret_cast<const uint8_t*>(kPlatformSpecificText.data()), + kPlatformSpecificText.size()); { ScopedClipboardWriter clipboard_writer(ClipboardBuffer::kCopyPaste); - clipboard_writer.WriteData(UTF8ToUTF16(kFormatString), + clipboard_writer.WriteData(ASCIIToUTF16(kFormatString), mojo_base::BigBuffer(text_span)); } @@ -758,27 +781,32 @@ TYPED_TEST(ClipboardTest, WindowsPredefinedFormatWriteDataTest) { ClipboardBuffer::kCopyPaste); EXPECT_THAT(raw_types, Contains(ASCIIToUTF16(kFormatString))); + +#if defined(OS_WIN) + // Only Windows ClipboardFormatType recognizes ANSI formats. EXPECT_TRUE(this->clipboard().IsFormatAvailable( ClipboardFormatType::GetPlainTextAType(), ClipboardBuffer::kCopyPaste)); +#endif // defined(OS_WIN) - // Only ClipboardWin recognizes the Windows-specific CF_TEXT. - std::string test_suite_name = ::testing::UnitTest::GetInstance() - ->current_test_info() - ->test_suite_name(); - if (test_suite_name == std::string("ClipboardTest/PlatformClipboardTest")) { - std::string text_result; - this->clipboard().ReadAsciiText(ClipboardBuffer::kCopyPaste, &text_result); - EXPECT_EQ(text, text_result); - - // Windows will automatically convert CF_TEXT to its UNICODE version. - EXPECT_TRUE(this->clipboard().IsFormatAvailable( - ClipboardFormatType::GetPlainTextType(), ClipboardBuffer::kCopyPaste)); - base::string16 text_result16; - this->clipboard().ReadText(ClipboardBuffer::kCopyPaste, &text_result16); - EXPECT_EQ(base::ASCIIToUTF16(text), text_result16); - } + EXPECT_TRUE(this->clipboard().IsFormatAvailable( + ClipboardFormatType::GetPlainTextType(), ClipboardBuffer::kCopyPaste)); + + std::string text_result; + this->clipboard().ReadAsciiText(ClipboardBuffer::kCopyPaste, &text_result); + EXPECT_EQ(text_result, text); + // Note: Windows will automatically convert CF_TEXT to its UNICODE version. + EXPECT_TRUE(this->clipboard().IsFormatAvailable( + ClipboardFormatType::GetPlainTextType(), ClipboardBuffer::kCopyPaste)); + base::string16 text_result16; + this->clipboard().ReadText(ClipboardBuffer::kCopyPaste, &text_result16); + EXPECT_EQ(text_result16, base::ASCIIToUTF16(text)); + + std::string platform_specific_result; + this->clipboard().ReadData(ClipboardFormatType::GetType(kFormatString), + &platform_specific_result); + EXPECT_EQ(platform_specific_result, kPlatformSpecificText); } -#endif +#endif // defined(OS_WIN) || defined(USE_X11) #if !defined(OS_MACOSX) && !defined(OS_ANDROID) TYPED_TEST(ClipboardTest, HyperlinkTest) { diff --git a/chromium/ui/base/clipboard/clipboard_util_mac.mm b/chromium/ui/base/clipboard/clipboard_util_mac.mm index a748d4af65a..8db45d20a2a 100644 --- a/chromium/ui/base/clipboard/clipboard_util_mac.mm +++ b/chromium/ui/base/clipboard/clipboard_util_mac.mm @@ -7,6 +7,7 @@ #include "base/mac/foundation_util.h" #import "base/mac/mac_util.h" #include "base/mac/scoped_cftyperef.h" +#include "base/notreached.h" namespace ui { diff --git a/chromium/ui/base/clipboard/clipboard_win.cc b/chromium/ui/base/clipboard/clipboard_win.cc index 9bfabd34eab..421f22eaaf6 100644 --- a/chromium/ui/base/clipboard/clipboard_win.cc +++ b/chromium/ui/base/clipboard/clipboard_win.cc @@ -30,6 +30,7 @@ #include "skia/ext/skia_utils_win.h" #include "third_party/skia/include/core/SkBitmap.h" #include "ui/base/clipboard/clipboard_constants.h" +#include "ui/base/clipboard/clipboard_metrics.h" #include "ui/base/clipboard/clipboard_util_win.h" #include "ui/base/clipboard/custom_data_helper.h" #include "ui/gfx/canvas.h" @@ -319,6 +320,7 @@ ClipboardWin::ReadAvailablePlatformSpecificFormatNames( void ClipboardWin::ReadText(ClipboardBuffer buffer, base::string16* result) const { DCHECK_EQ(buffer, ClipboardBuffer::kCopyPaste); + RecordRead(ClipboardFormatMetric::kText); if (!result) { NOTREACHED(); return; @@ -344,6 +346,7 @@ void ClipboardWin::ReadText(ClipboardBuffer buffer, void ClipboardWin::ReadAsciiText(ClipboardBuffer buffer, std::string* result) const { DCHECK_EQ(buffer, ClipboardBuffer::kCopyPaste); + RecordRead(ClipboardFormatMetric::kText); if (!result) { NOTREACHED(); return; @@ -372,6 +375,7 @@ void ClipboardWin::ReadHTML(ClipboardBuffer buffer, uint32_t* fragment_start, uint32_t* fragment_end) const { DCHECK_EQ(buffer, ClipboardBuffer::kCopyPaste); + RecordRead(ClipboardFormatMetric::kHtml); markup->clear(); // TODO(dcheng): Remove these checks, I don't think they should be optional. @@ -425,6 +429,7 @@ void ClipboardWin::ReadHTML(ClipboardBuffer buffer, void ClipboardWin::ReadRTF(ClipboardBuffer buffer, std::string* result) const { DCHECK_EQ(buffer, ClipboardBuffer::kCopyPaste); + RecordRead(ClipboardFormatMetric::kRtf); ReadData(ClipboardFormatType::GetRtfType(), result); TrimAfterNull(result); @@ -432,6 +437,7 @@ void ClipboardWin::ReadRTF(ClipboardBuffer buffer, std::string* result) const { void ClipboardWin::ReadImage(ClipboardBuffer buffer, ReadImageCallback callback) const { + RecordRead(ClipboardFormatMetric::kImage); std::move(callback).Run(ReadImageInternal(buffer)); } @@ -439,6 +445,7 @@ void ClipboardWin::ReadCustomData(ClipboardBuffer buffer, const base::string16& type, base::string16* result) const { DCHECK_EQ(buffer, ClipboardBuffer::kCopyPaste); + RecordRead(ClipboardFormatMetric::kCustomData); // Acquire the clipboard. ScopedClipboard clipboard; @@ -455,6 +462,7 @@ void ClipboardWin::ReadCustomData(ClipboardBuffer buffer, } void ClipboardWin::ReadBookmark(base::string16* title, std::string* url) const { + RecordRead(ClipboardFormatMetric::kBookmark); if (title) title->clear(); @@ -481,6 +489,7 @@ void ClipboardWin::ReadBookmark(base::string16* title, std::string* url) const { void ClipboardWin::ReadData(const ClipboardFormatType& format, std::string* result) const { + RecordRead(ClipboardFormatMetric::kData); if (!result) { NOTREACHED(); return; diff --git a/chromium/ui/base/clipboard/clipboard_x11.cc b/chromium/ui/base/clipboard/clipboard_x11.cc index 95e2caff21a..c2f3620584b 100644 --- a/chromium/ui/base/clipboard/clipboard_x11.cc +++ b/chromium/ui/base/clipboard/clipboard_x11.cc @@ -22,8 +22,10 @@ #include "base/strings/utf_string_conversions.h" #include "third_party/skia/include/core/SkBitmap.h" #include "ui/base/clipboard/clipboard_constants.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/nine_image_painter_factory.h" #include "ui/base/x/selection_owner.h" #include "ui/base/x/selection_requestor.h" #include "ui/base/x/selection_utils.h" @@ -32,8 +34,12 @@ #include "ui/events/x/x11_window_event_manager.h" #include "ui/gfx/codec/png_codec.h" #include "ui/gfx/geometry/size.h" +#include "ui/gfx/x/connection.h" +#include "ui/gfx/x/event.h" #include "ui/gfx/x/x11.h" #include "ui/gfx/x/x11_atom_cache.h" +#include "ui/gfx/x/xfixes.h" +#include "ui/gfx/x/xproto.h" namespace ui { @@ -61,63 +67,57 @@ class SelectionChangeObserver : public XEventObserver { ~SelectionChangeObserver() override; // XEventObserver: - void WillProcessXEvent(XEvent* xev) override; - void DidProcessXEvent(XEvent* xev) override {} + void WillProcessXEvent(x11::Event* xev) override; + void DidProcessXEvent(x11::Event* xev) override {} - int event_base_; - Atom clipboard_atom_; - uint64_t clipboard_sequence_number_; - uint64_t primary_sequence_number_; + x11::Atom clipboard_atom_{}; + uint64_t clipboard_sequence_number_{}; + uint64_t primary_sequence_number_{}; DISALLOW_COPY_AND_ASSIGN(SelectionChangeObserver); }; -SelectionChangeObserver::SelectionChangeObserver() - : event_base_(-1), - clipboard_atom_(x11::None), - clipboard_sequence_number_(0), - primary_sequence_number_(0) { - int ignored; - if (XFixesQueryExtension(gfx::GetXDisplay(), &event_base_, &ignored)) { - clipboard_atom_ = gfx::GetAtom(kClipboard); - XFixesSelectSelectionInput(gfx::GetXDisplay(), GetX11RootWindow(), - clipboard_atom_, - XFixesSetSelectionOwnerNotifyMask | - XFixesSelectionWindowDestroyNotifyMask | - XFixesSelectionClientCloseNotifyMask); - // This seems to be semi-optional. For some reason, registering for any - // selection notify events seems to subscribe us to events for both the - // primary and the clipboard buffers. Register anyway just to be safe. - XFixesSelectSelectionInput(gfx::GetXDisplay(), GetX11RootWindow(), - XA_PRIMARY, - XFixesSetSelectionOwnerNotifyMask | - XFixesSelectionWindowDestroyNotifyMask | - XFixesSelectionClientCloseNotifyMask); - - X11EventSource::GetInstance()->AddXEventObserver(this); - } -} +SelectionChangeObserver::SelectionChangeObserver() { + auto& xfixes = x11::Connection::Get()->xfixes(); + // Let the server know the client version. No need to sync since we don't + // care what version is running on the server. + xfixes.QueryVersion({x11::XFixes::major_version, x11::XFixes::minor_version}); + if (!xfixes.present()) + return; + + clipboard_atom_ = gfx::GetAtom(kClipboard); + auto mask = x11::XFixes::SelectionEventMask::SetSelectionOwner | + x11::XFixes::SelectionEventMask::SelectionWindowDestroy | + x11::XFixes::SelectionEventMask::SelectionClientClose; + xfixes.SelectSelectionInput({GetX11RootWindow(), clipboard_atom_, mask}); + // This seems to be semi-optional. For some reason, registering for any + // selection notify events seems to subscribe us to events for both the + // primary and the clipboard buffers. Register anyway just to be safe. + xfixes.SelectSelectionInput({GetX11RootWindow(), x11::Atom::PRIMARY, mask}); -SelectionChangeObserver::~SelectionChangeObserver() { - // We are a singleton; we will outlive the event source. + X11EventSource::GetInstance()->AddXEventObserver(this); } +// We are a singleton; we will outlive the event source. +SelectionChangeObserver::~SelectionChangeObserver() = default; + SelectionChangeObserver* SelectionChangeObserver::GetInstance() { return base::Singleton<SelectionChangeObserver>::get(); } -void SelectionChangeObserver::WillProcessXEvent(XEvent* xev) { - if (xev->type == event_base_ + XFixesSelectionNotify) { - XFixesSelectionNotifyEvent* ev = - reinterpret_cast<XFixesSelectionNotifyEvent*>(xev); - if (ev->selection == clipboard_atom_) { - clipboard_sequence_number_++; - ClipboardMonitor::GetInstance()->NotifyClipboardDataChanged(); - } else if (ev->selection == XA_PRIMARY) { - primary_sequence_number_++; - } else { - DLOG(ERROR) << "Unexpected selection atom: " << ev->selection; - } +void SelectionChangeObserver::WillProcessXEvent(x11::Event* xev) { + auto* ev = xev->As<x11::XFixes::SelectionNotifyEvent>(); + if (!ev) + return; + + if (static_cast<x11::Atom>(ev->selection) == clipboard_atom_) { + clipboard_sequence_number_++; + ClipboardMonitor::GetInstance()->NotifyClipboardDataChanged(); + } else if (ev->selection == x11::Atom::PRIMARY) { + primary_sequence_number_++; + } else { + DLOG(ERROR) << "Unexpected selection atom: " + << static_cast<uint32_t>(ev->selection); } } @@ -126,7 +126,7 @@ void SelectionChangeObserver::WillProcessXEvent(XEvent* xev) { // Represents a list of possible return types. Copy constructable. class TargetList { public: - using AtomVector = std::vector<::Atom>; + using AtomVector = std::vector<x11::Atom>; explicit TargetList(const AtomVector& target_list); @@ -134,7 +134,7 @@ class TargetList { bool ContainsText() const; bool ContainsFormat(const ClipboardFormatType& format_type) const; - bool ContainsAtom(::Atom atom) const; + bool ContainsAtom(x11::Atom atom) const; private: AtomVector target_list_; @@ -144,7 +144,7 @@ TargetList::TargetList(const AtomVector& target_list) : target_list_(target_list) {} bool TargetList::ContainsText() const { - std::vector<::Atom> atoms = GetTextAtomsFrom(); + std::vector<x11::Atom> atoms = GetTextAtomsFrom(); for (const auto& atom : atoms) { if (ContainsAtom(atom)) return true; @@ -154,14 +154,19 @@ bool TargetList::ContainsText() const { } bool TargetList::ContainsFormat(const ClipboardFormatType& format_type) const { - ::Atom atom = gfx::GetAtom(format_type.GetName().c_str()); + x11::Atom atom = gfx::GetAtom(format_type.GetName().c_str()); return ContainsAtom(atom); } -bool TargetList::ContainsAtom(::Atom atom) const { +bool TargetList::ContainsAtom(x11::Atom atom) const { return base::Contains(target_list_, atom); } +x11::Window GetSelectionOwner(x11::Atom selection) { + auto response = x11::Connection::Get()->GetSelectionOwner({selection}).Sync(); + return response ? response->owner : x11::Window::None; +} + } // namespace /////////////////////////////////////////////////////////////////////////////// @@ -176,14 +181,14 @@ class ClipboardX11::X11Details : public XEventDispatcher { // Returns the X11 selection atom that we pass to various XSelection functions // for the given buffer. - ::Atom LookupSelectionForClipboardBuffer(ClipboardBuffer buffer) const; + x11::Atom LookupSelectionForClipboardBuffer(ClipboardBuffer buffer) const; // Returns the X11 selection atom that we pass to various XSelection functions // for ClipboardBuffer::kCopyPaste. - ::Atom GetCopyPasteSelection() const; + x11::Atom GetCopyPasteSelection() const; // Finds the SelectionFormatMap for the incoming selection atom. - const SelectionFormatMap& LookupStorageForAtom(::Atom atom); + const SelectionFormatMap& LookupStorageForAtom(x11::Atom atom); // As we need to collect all the data types before we tell X11 that we own a // particular selection, we create a temporary clipboard mapping that @@ -208,7 +213,7 @@ class ClipboardX11::X11Details : public XEventDispatcher { // and do the asynchronous dance with whatever application is holding the // selection. SelectionData RequestAndWaitForTypes(ClipboardBuffer buffer, - const std::vector<::Atom>& types); + const std::vector<x11::Atom>& types); // Retrieves the list of possible data types the current clipboard owner has. // @@ -217,10 +222,10 @@ class ClipboardX11::X11Details : public XEventDispatcher { TargetList WaitAndGetTargetsList(ClipboardBuffer buffer); // Returns a list of all text atoms that we handle. - std::vector<::Atom> GetTextAtoms() const; + std::vector<x11::Atom> GetTextAtoms() const; // Returns a vector with a |format| converted to an X11 atom. - std::vector<::Atom> GetAtomsForFormat(const ClipboardFormatType& format); + std::vector<x11::Atom> GetAtomsForFormat(const ClipboardFormatType& format); // Clears a certain clipboard buffer, whether we own it or not. void Clear(ClipboardBuffer buffer); @@ -231,16 +236,14 @@ class ClipboardX11::X11Details : public XEventDispatcher { private: // XEventDispatcher: - bool DispatchXEvent(XEvent* xev) override; - - bool CanDispatchXEvent(XEvent* xev); + bool DispatchXEvent(x11::Event* xev) override; // Our X11 state. - Display* x_display_; - ::Window x_root_window_; + x11::Connection* connection_; + x11::Window x_root_window_; // Input-only window used as a selection owner. - ::Window x_window_; + x11::Window x_window_; // Events selected on |x_window_|. std::unique_ptr<XScopedEventSelector> x_window_events_; @@ -259,26 +262,16 @@ class ClipboardX11::X11Details : public XEventDispatcher { }; ClipboardX11::X11Details::X11Details() - : x_display_(gfx::GetXDisplay()), - x_root_window_(DefaultRootWindow(x_display_)), - x_window_(XCreateWindow(x_display_, - x_root_window_, - -100, - -100, - 10, - 10, // x, y, width, height - 0, // border width - CopyFromParent, // depth - InputOnly, - CopyFromParent, // visual - 0, - nullptr)), - selection_requestor_(x_display_, x_window_, this), - clipboard_owner_(x_display_, x_window_, gfx::GetAtom(kClipboard)), - primary_owner_(x_display_, x_window_, XA_PRIMARY) { - XStoreName(x_display_, x_window_, "Chromium clipboard"); - x_window_events_.reset( - new XScopedEventSelector(x_window_, PropertyChangeMask)); + : connection_(x11::Connection::Get()), + x_root_window_(ui::GetX11RootWindow()), + x_window_(CreateDummyWindow("Chromium Clipboard Window")), + selection_requestor_(x_window_, this), + clipboard_owner_(connection_, x_window_, gfx::GetAtom(kClipboard)), + primary_owner_(connection_, x_window_, x11::Atom::PRIMARY) { + SetStringProperty(x_window_, x11::Atom::WM_NAME, x11::Atom::STRING, + "Chromium clipboard"); + x_window_events_ = + std::make_unique<XScopedEventSelector>(x_window_, PropertyChangeMask); if (X11EventSource::GetInstance()) X11EventSource::GetInstance()->AddXEventDispatcher(this); @@ -288,24 +281,24 @@ ClipboardX11::X11Details::~X11Details() { if (X11EventSource::GetInstance()) X11EventSource::GetInstance()->RemoveXEventDispatcher(this); - XDestroyWindow(x_display_, x_window_); + connection_->DestroyWindow({x_window_}); } -::Atom ClipboardX11::X11Details::LookupSelectionForClipboardBuffer( +x11::Atom ClipboardX11::X11Details::LookupSelectionForClipboardBuffer( ClipboardBuffer buffer) const { if (buffer == ClipboardBuffer::kCopyPaste) return GetCopyPasteSelection(); - return XA_PRIMARY; + return x11::Atom::PRIMARY; } -::Atom ClipboardX11::X11Details::GetCopyPasteSelection() const { +x11::Atom ClipboardX11::X11Details::GetCopyPasteSelection() const { return gfx::GetAtom(kClipboard); } const SelectionFormatMap& ClipboardX11::X11Details::LookupStorageForAtom( - ::Atom atom) { - if (atom == XA_PRIMARY) + x11::Atom atom) { + if (atom == x11::Atom::PRIMARY) return primary_owner_.selection_format_map(); DCHECK_EQ(GetCopyPasteSelection(), atom); @@ -319,7 +312,7 @@ void ClipboardX11::X11Details::CreateNewClipboardData() { void ClipboardX11::X11Details::InsertMapping( const std::string& key, const scoped_refptr<base::RefCountedMemory>& memory) { - ::Atom atom_key = gfx::GetAtom(key.c_str()); + x11::Atom atom_key = gfx::GetAtom(key.c_str()); clipboard_data_.Insert(atom_key, memory); } @@ -333,9 +326,9 @@ void ClipboardX11::X11Details::TakeOwnershipOfSelection( SelectionData ClipboardX11::X11Details::RequestAndWaitForTypes( ClipboardBuffer buffer, - const std::vector<::Atom>& types) { - ::Atom selection_name = LookupSelectionForClipboardBuffer(buffer); - if (XGetSelectionOwner(x_display_, selection_name) == x_window_) { + const std::vector<x11::Atom>& types) { + x11::Atom selection_name = LookupSelectionForClipboardBuffer(buffer); + if (GetSelectionOwner(selection_name) == x_window_) { // We can local fastpath instead of playing the nested run loop game // with the X server. const SelectionFormatMap& format_map = LookupStorageForAtom(selection_name); @@ -348,8 +341,8 @@ SelectionData ClipboardX11::X11Details::RequestAndWaitForTypes( } else { TargetList targets = WaitAndGetTargetsList(buffer); - ::Atom selection_name = LookupSelectionForClipboardBuffer(buffer); - std::vector<::Atom> intersection; + x11::Atom selection_name = LookupSelectionForClipboardBuffer(buffer); + std::vector<x11::Atom> intersection; GetAtomIntersection(types, targets.target_list(), &intersection); return selection_requestor_.RequestAndWaitForTypes(selection_name, intersection); @@ -360,27 +353,25 @@ SelectionData ClipboardX11::X11Details::RequestAndWaitForTypes( TargetList ClipboardX11::X11Details::WaitAndGetTargetsList( ClipboardBuffer buffer) { - ::Atom selection_name = LookupSelectionForClipboardBuffer(buffer); - std::vector<::Atom> out; - if (XGetSelectionOwner(x_display_, selection_name) == x_window_) { + x11::Atom selection_name = LookupSelectionForClipboardBuffer(buffer); + std::vector<x11::Atom> out; + if (GetSelectionOwner(selection_name) == x_window_) { // We can local fastpath and return the list of local targets. const SelectionFormatMap& format_map = LookupStorageForAtom(selection_name); for (const auto& format : format_map) out.push_back(format.first); } else { - scoped_refptr<base::RefCountedMemory> data; - size_t out_data_items = 0; - ::Atom out_type = x11::None; + std::vector<uint8_t> data; + x11::Atom out_type = x11::Atom::None; if (selection_requestor_.PerformBlockingConvertSelection( - selection_name, gfx::GetAtom(kTargets), &data, &out_data_items, - &out_type)) { + selection_name, gfx::GetAtom(kTargets), &data, &out_type)) { // Some apps return an |out_type| of "TARGETS". (crbug.com/377893) - if (out_type == XA_ATOM || out_type == gfx::GetAtom(kTargets)) { - const ::Atom* atom_array = - reinterpret_cast<const ::Atom*>(data->front()); - for (size_t i = 0; i < out_data_items; ++i) + if (out_type == x11::Atom::ATOM || out_type == gfx::GetAtom(kTargets)) { + const x11::Atom* atom_array = + reinterpret_cast<const x11::Atom*>(data.data()); + for (size_t i = 0; i < data.size() / sizeof(x11::Atom); ++i) out.push_back(atom_array[i]); } } else { @@ -390,11 +381,11 @@ TargetList ClipboardX11::X11Details::WaitAndGetTargetsList( // text. This is pretty unfortunate since it means we have to actually // copy the data to see if it is available, but at least this path // shouldn't be hit for conforming programs. - std::vector<::Atom> types = GetTextAtoms(); + std::vector<x11::Atom> types = GetTextAtoms(); for (const auto& text_atom : types) { - ::Atom type = x11::None; + x11::Atom type = x11::Atom::None; if (selection_requestor_.PerformBlockingConvertSelection( - selection_name, text_atom, nullptr, nullptr, &type) && + selection_name, text_atom, nullptr, &type) && type == text_atom) { out.push_back(text_atom); } @@ -405,11 +396,11 @@ TargetList ClipboardX11::X11Details::WaitAndGetTargetsList( return TargetList(out); } -std::vector<::Atom> ClipboardX11::X11Details::GetTextAtoms() const { +std::vector<x11::Atom> ClipboardX11::X11Details::GetTextAtoms() const { return GetTextAtomsFrom(); } -std::vector<::Atom> ClipboardX11::X11Details::GetAtomsForFormat( +std::vector<x11::Atom> ClipboardX11::X11Details::GetAtomsForFormat( const ClipboardFormatType& format) { return {gfx::GetAtom(format.GetName().c_str())}; } @@ -422,18 +413,18 @@ void ClipboardX11::X11Details::Clear(ClipboardBuffer buffer) { } void ClipboardX11::X11Details::StoreCopyPasteDataAndWait() { - ::Atom selection = GetCopyPasteSelection(); - if (XGetSelectionOwner(x_display_, selection) != x_window_) + x11::Atom selection = GetCopyPasteSelection(); + if (GetSelectionOwner(selection) != x_window_) return; - ::Atom clipboard_manager_atom = gfx::GetAtom(kClipboardManager); - if (XGetSelectionOwner(x_display_, clipboard_manager_atom) == x11::None) + x11::Atom clipboard_manager_atom = gfx::GetAtom(kClipboardManager); + if (GetSelectionOwner(clipboard_manager_atom) == x11::Window::None) return; const SelectionFormatMap& format_map = LookupStorageForAtom(selection); if (format_map.size() == 0) return; - std::vector<Atom> targets = format_map.GetTypes(); + std::vector<x11::Atom> targets = format_map.GetTypes(); base::TimeTicks start = base::TimeTicks::Now(); selection_requestor_.PerformBlockingConvertSelectionWithParameter( @@ -442,71 +433,45 @@ void ClipboardX11::X11Details::StoreCopyPasteDataAndWait() { base::TimeTicks::Now() - start); } -bool ClipboardX11::X11Details::CanDispatchXEvent(XEvent* xev) { - if (xev->xany.window == x_window_) - return true; - - if (xev->type == PropertyNotify) { - return primary_owner_.CanDispatchPropertyEvent(*xev) || - clipboard_owner_.CanDispatchPropertyEvent(*xev) || - selection_requestor_.CanDispatchPropertyEvent(*xev); - } - return false; -} - -bool ClipboardX11::X11Details::DispatchXEvent(XEvent* xev) { - if (!CanDispatchXEvent(xev)) - return false; - - switch (xev->type) { - case SelectionRequest: { - if (xev->xselectionrequest.selection == XA_PRIMARY) { - primary_owner_.OnSelectionRequest(*xev); - } else { - // We should not get requests for the CLIPBOARD_MANAGER selection - // because we never take ownership of it. - DCHECK_EQ(GetCopyPasteSelection(), xev->xselectionrequest.selection); - clipboard_owner_.OnSelectionRequest(*xev); - } - break; - } - case SelectionNotify: { - selection_requestor_.OnSelectionNotify(*xev); - break; - } - case SelectionClear: { - if (xev->xselectionclear.selection == XA_PRIMARY) { - primary_owner_.OnSelectionClear(*xev); - } else { - // We should not get requests for the CLIPBOARD_MANAGER selection - // because we never take ownership of it. - DCHECK_EQ(GetCopyPasteSelection(), xev->xselection.selection); - clipboard_owner_.OnSelectionClear(*xev); - } - break; +bool ClipboardX11::X11Details::DispatchXEvent(x11::Event* xev) { + if (auto* request = xev->As<x11::SelectionRequestEvent>()) { + if (request->owner != x_window_) + return false; + if (request->selection == x11::Atom::PRIMARY) { + primary_owner_.OnSelectionRequest(*xev); + } else { + // We should not get requests for the CLIPBOARD_MANAGER selection + // because we never take ownership of it. + DCHECK_EQ(GetCopyPasteSelection(), request->selection); + clipboard_owner_.OnSelectionRequest(*xev); } - case PropertyNotify: { - if (primary_owner_.CanDispatchPropertyEvent(*xev)) - primary_owner_.OnPropertyEvent(*xev); - if (clipboard_owner_.CanDispatchPropertyEvent(*xev)) - clipboard_owner_.OnPropertyEvent(*xev); - if (selection_requestor_.CanDispatchPropertyEvent(*xev)) - selection_requestor_.OnPropertyEvent(*xev); - break; + } else if (auto* notify = xev->As<x11::SelectionNotifyEvent>()) { + if (notify->requestor != x_window_) + return false; + selection_requestor_.OnSelectionNotify(*notify); + } else if (auto* clear = xev->As<x11::SelectionClearEvent>()) { + if (clear->owner != x_window_) + return false; + if (clear->selection == x11::Atom::PRIMARY) { + primary_owner_.OnSelectionClear(*xev); + } else { + // We should not get requests for the CLIPBOARD_MANAGER selection + // because we never take ownership of it. + DCHECK_EQ(GetCopyPasteSelection(), clear->selection); + clipboard_owner_.OnSelectionClear(*xev); } - default: - break; + } else if (auto* prop = xev->As<x11::PropertyNotifyEvent>()) { + if (primary_owner_.CanDispatchPropertyEvent(*xev)) + primary_owner_.OnPropertyEvent(*xev); + if (clipboard_owner_.CanDispatchPropertyEvent(*xev)) + clipboard_owner_.OnPropertyEvent(*xev); + if (selection_requestor_.CanDispatchPropertyEvent(*xev)) + selection_requestor_.OnPropertyEvent(*xev); } return false; } /////////////////////////////////////////////////////////////////////////////// -// Clipboard factory method. -Clipboard* Clipboard::Create() { - return new ClipboardX11; -} - -/////////////////////////////////////////////////////////////////////////////// // ClipboardX11 ClipboardX11::ClipboardX11() : x11_details_(new X11Details) { @@ -586,17 +551,16 @@ ClipboardX11::ReadAvailablePlatformSpecificFormatNames( if (target_list.empty()) return {}; - std::vector<char*> types_buffer(target_list.size()); - // Call XGetAtomNames to minimize trips to the X11 server. - int status = XGetAtomNames(gfx::GetXDisplay(), target_list.data(), - target_list.size(), types_buffer.data()); - DCHECK(status) << "XGetAtomNames failed! An invalid Atom was passed in."; - + std::vector<x11::Future<x11::GetAtomNameReply>> futures; + for (x11::Atom target : target_list) + futures.push_back(x11::Connection::Get()->GetAtomName({target})); std::vector<base::string16> types; types.reserve(target_list.size()); - for (char* type : types_buffer) { - types.push_back(base::UTF8ToUTF16(type)); - XFree(type); + for (auto& future : futures) { + if (auto response = future.Sync()) + types.push_back(base::UTF8ToUTF16(response->name)); + else + types.emplace_back(); } return types; @@ -605,6 +569,7 @@ ClipboardX11::ReadAvailablePlatformSpecificFormatNames( void ClipboardX11::ReadText(ClipboardBuffer buffer, base::string16* result) const { DCHECK(CalledOnValidThread()); + RecordRead(ClipboardFormatMetric::kText); SelectionData data(x11_details_->RequestAndWaitForTypes( buffer, x11_details_->GetTextAtoms())); @@ -617,6 +582,7 @@ void ClipboardX11::ReadText(ClipboardBuffer buffer, void ClipboardX11::ReadAsciiText(ClipboardBuffer buffer, std::string* result) const { DCHECK(CalledOnValidThread()); + RecordRead(ClipboardFormatMetric::kText); SelectionData data(x11_details_->RequestAndWaitForTypes( buffer, x11_details_->GetTextAtoms())); @@ -632,6 +598,7 @@ void ClipboardX11::ReadHTML(ClipboardBuffer buffer, uint32_t* fragment_start, uint32_t* fragment_end) const { DCHECK(CalledOnValidThread()); + RecordRead(ClipboardFormatMetric::kHtml); markup->clear(); if (src_url) src_url->clear(); @@ -652,6 +619,7 @@ void ClipboardX11::ReadHTML(ClipboardBuffer buffer, void ClipboardX11::ReadRTF(ClipboardBuffer buffer, std::string* result) const { DCHECK(CalledOnValidThread()); + RecordRead(ClipboardFormatMetric::kRtf); SelectionData data(x11_details_->RequestAndWaitForTypes( buffer, @@ -663,6 +631,7 @@ void ClipboardX11::ReadRTF(ClipboardBuffer buffer, std::string* result) const { void ClipboardX11::ReadImage(ClipboardBuffer buffer, ReadImageCallback callback) const { DCHECK(IsSupportedClipboardBuffer(buffer)); + RecordRead(ClipboardFormatMetric::kImage); std::move(callback).Run(ReadImageInternal(buffer)); } @@ -670,6 +639,7 @@ void ClipboardX11::ReadCustomData(ClipboardBuffer buffer, const base::string16& type, base::string16* result) const { DCHECK(CalledOnValidThread()); + RecordRead(ClipboardFormatMetric::kCustomData); SelectionData data(x11_details_->RequestAndWaitForTypes( buffer, x11_details_->GetAtomsForFormat( @@ -687,6 +657,7 @@ void ClipboardX11::ReadBookmark(base::string16* title, std::string* url) const { void ClipboardX11::ReadData(const ClipboardFormatType& format, std::string* result) const { DCHECK(CalledOnValidThread()); + RecordRead(ClipboardFormatMetric::kData); SelectionData data(x11_details_->RequestAndWaitForTypes( ClipboardBuffer::kCopyPaste, x11_details_->GetAtomsForFormat(format))); diff --git a/chromium/ui/base/clipboard/scoped_clipboard_writer.cc b/chromium/ui/base/clipboard/scoped_clipboard_writer.cc index 1b8312f5fc5..c723b0d2e33 100644 --- a/chromium/ui/base/clipboard/scoped_clipboard_writer.cc +++ b/chromium/ui/base/clipboard/scoped_clipboard_writer.cc @@ -8,6 +8,7 @@ #include "base/strings/utf_string_conversions.h" #include "net/base/escape.h" #include "ui/base/clipboard/clipboard_format_type.h" +#include "ui/base/clipboard/clipboard_metrics.h" #include "ui/gfx/geometry/size.h" // Documentation on the format of the parameters for each clipboard target can @@ -31,9 +32,12 @@ ScopedClipboardWriter::~ScopedClipboardWriter() { Clipboard::GetForCurrentThread()->WritePlatformRepresentations( buffer_, std::move(platform_representations_)); } + if (confidential_) + Clipboard::GetForCurrentThread()->MarkAsConfidential(); } void ScopedClipboardWriter::WriteText(const base::string16& text) { + RecordWrite(ClipboardFormatMetric::kText); std::string utf8_text = base::UTF16ToUTF8(text); Clipboard::ObjectMapParams parameters; @@ -44,6 +48,7 @@ void ScopedClipboardWriter::WriteText(const base::string16& text) { void ScopedClipboardWriter::WriteHTML(const base::string16& markup, const std::string& source_url) { + RecordWrite(ClipboardFormatMetric::kHtml); std::string utf8_markup = base::UTF16ToUTF8(markup); Clipboard::ObjectMapParams parameters; @@ -59,6 +64,7 @@ void ScopedClipboardWriter::WriteHTML(const base::string16& markup, } void ScopedClipboardWriter::WriteRTF(const std::string& rtf_data) { + RecordWrite(ClipboardFormatMetric::kRtf); Clipboard::ObjectMapParams parameters; parameters.push_back(Clipboard::ObjectMapParam(rtf_data.begin(), rtf_data.end())); @@ -69,6 +75,7 @@ void ScopedClipboardWriter::WriteBookmark(const base::string16& bookmark_title, const std::string& url) { if (bookmark_title.empty() || url.empty()) return; + RecordWrite(ClipboardFormatMetric::kBookmark); std::string utf8_markup = base::UTF16ToUTF8(bookmark_title); @@ -94,6 +101,7 @@ void ScopedClipboardWriter::WriteHyperlink(const base::string16& anchor_text, } void ScopedClipboardWriter::WriteWebSmartPaste() { + RecordWrite(ClipboardFormatMetric::kWebSmartPaste); objects_[Clipboard::PortableFormat::kWebkit] = Clipboard::ObjectMapParams(); } @@ -101,6 +109,7 @@ void ScopedClipboardWriter::WriteImage(const SkBitmap& bitmap) { if (bitmap.drawsNothing()) return; DCHECK(bitmap.getPixels()); + RecordWrite(ClipboardFormatMetric::kImage); bitmap_ = bitmap; // TODO(dcheng): This is slightly less horrible than what we used to do, but @@ -114,9 +123,14 @@ void ScopedClipboardWriter::WriteImage(const SkBitmap& bitmap) { objects_[Clipboard::PortableFormat::kBitmap] = parameters; } +void ScopedClipboardWriter::MarkAsConfidential() { + confidential_ = true; +} + void ScopedClipboardWriter::WritePickledData( const base::Pickle& pickle, const ClipboardFormatType& format) { + RecordWrite(ClipboardFormatMetric::kCustomData); std::string format_string = format.Serialize(); Clipboard::ObjectMapParam format_parameter(format_string.begin(), format_string.end()); @@ -134,6 +148,7 @@ void ScopedClipboardWriter::WritePickledData( void ScopedClipboardWriter::WriteData(const base::string16& format, mojo_base::BigBuffer data) { + RecordWrite(ClipboardFormatMetric::kData); platform_representations_.push_back( {base::UTF16ToUTF8(format), std::move(data)}); } @@ -142,6 +157,7 @@ void ScopedClipboardWriter::Reset() { objects_.clear(); platform_representations_.clear(); bitmap_.reset(); + confidential_ = false; } } // namespace ui diff --git a/chromium/ui/base/clipboard/scoped_clipboard_writer.h b/chromium/ui/base/clipboard/scoped_clipboard_writer.h index d0e5cfb3e3e..d2ed3736ce2 100644 --- a/chromium/ui/base/clipboard/scoped_clipboard_writer.h +++ b/chromium/ui/base/clipboard/scoped_clipboard_writer.h @@ -67,6 +67,9 @@ class COMPONENT_EXPORT(UI_BASE_CLIPBOARD) ScopedClipboardWriter { void WriteImage(const SkBitmap& bitmap); + // Mark the data to be written as confidential. + void MarkAsConfidential(); + // Removes all objects that would be written to the clipboard. void Reset(); @@ -83,6 +86,8 @@ class COMPONENT_EXPORT(UI_BASE_CLIPBOARD) ScopedClipboardWriter { SkBitmap bitmap_; + bool confidential_ = false; + DISALLOW_COPY_AND_ASSIGN(ScopedClipboardWriter); }; |