clipboard_history_util.cc 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. // Copyright 2020 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "ash/clipboard/clipboard_history_util.h"
  5. #include <array>
  6. #include "ash/clipboard/clipboard_history_item.h"
  7. #include "ash/metrics/histogram_macros.h"
  8. #include "ash/resources/vector_icons/vector_icons.h"
  9. #include "ash/session/session_controller_impl.h"
  10. #include "ash/shell.h"
  11. #include "ash/style/ash_color_provider.h"
  12. #include "ash/style/dark_light_mode_controller_impl.h"
  13. #include "base/files/file_path.h"
  14. #include "base/strings/string_split.h"
  15. #include "base/strings/utf_string_conversions.h"
  16. #include "chromeos/ui/base/file_icon_util.h"
  17. #include "ui/base/clipboard/clipboard_data.h"
  18. #include "ui/base/clipboard/custom_data_helper.h"
  19. #include "ui/gfx/paint_vector_icon.h"
  20. namespace ash {
  21. namespace ClipboardHistoryUtil {
  22. namespace {
  23. constexpr char16_t kFileSystemSourcesType[] = u"fs/sources";
  24. // The array of formats in order of decreasing priority.
  25. constexpr ui::ClipboardInternalFormat kPrioritizedFormats[] = {
  26. ui::ClipboardInternalFormat::kPng,
  27. ui::ClipboardInternalFormat::kHtml,
  28. ui::ClipboardInternalFormat::kText,
  29. ui::ClipboardInternalFormat::kRtf,
  30. ui::ClipboardInternalFormat::kFilenames,
  31. ui::ClipboardInternalFormat::kBookmark,
  32. ui::ClipboardInternalFormat::kWeb,
  33. ui::ClipboardInternalFormat::kCustom};
  34. } // namespace
  35. absl::optional<ui::ClipboardInternalFormat> CalculateMainFormat(
  36. const ui::ClipboardData& data) {
  37. for (const auto& format : kPrioritizedFormats) {
  38. if (ContainsFormat(data, format)) {
  39. return format;
  40. }
  41. }
  42. return absl::nullopt;
  43. }
  44. ClipboardHistoryDisplayFormat CalculateDisplayFormat(
  45. const ui::ClipboardData& data) {
  46. switch (CalculateMainFormat(data).value()) {
  47. case ui::ClipboardInternalFormat::kPng:
  48. return ClipboardHistoryDisplayFormat::kPng;
  49. case ui::ClipboardInternalFormat::kHtml:
  50. if ((data.markup_data().find("<img") == std::string::npos) &&
  51. (data.markup_data().find("<table") == std::string::npos)) {
  52. return ClipboardHistoryDisplayFormat::kText;
  53. }
  54. return ClipboardHistoryDisplayFormat::kHtml;
  55. case ui::ClipboardInternalFormat::kText:
  56. case ui::ClipboardInternalFormat::kSvg:
  57. case ui::ClipboardInternalFormat::kRtf:
  58. case ui::ClipboardInternalFormat::kBookmark:
  59. case ui::ClipboardInternalFormat::kWeb:
  60. return ClipboardHistoryDisplayFormat::kText;
  61. case ui::ClipboardInternalFormat::kFilenames:
  62. return ClipboardHistoryDisplayFormat::kFile;
  63. case ui::ClipboardInternalFormat::kCustom:
  64. return ContainsFileSystemData(data)
  65. ? ClipboardHistoryDisplayFormat::kFile
  66. : ClipboardHistoryDisplayFormat::kText;
  67. }
  68. }
  69. bool ContainsFormat(const ui::ClipboardData& data,
  70. ui::ClipboardInternalFormat format) {
  71. return data.format() & static_cast<int>(format);
  72. }
  73. void RecordClipboardHistoryItemDeleted(const ClipboardHistoryItem& item) {
  74. UMA_HISTOGRAM_ENUMERATION(
  75. "Ash.ClipboardHistory.ContextMenu.DisplayFormatDeleted",
  76. CalculateDisplayFormat(item.data()));
  77. }
  78. void RecordClipboardHistoryItemPasted(const ClipboardHistoryItem& item) {
  79. UMA_HISTOGRAM_ENUMERATION(
  80. "Ash.ClipboardHistory.ContextMenu.DisplayFormatPasted",
  81. CalculateDisplayFormat(item.data()));
  82. }
  83. bool ContainsFileSystemData(const ui::ClipboardData& data) {
  84. return !GetFileSystemSources(data).empty();
  85. }
  86. void GetSplitFileSystemData(const ui::ClipboardData& data,
  87. std::vector<base::StringPiece16>* source_list,
  88. std::u16string* sources) {
  89. DCHECK(sources);
  90. DCHECK(sources->empty());
  91. DCHECK(source_list);
  92. DCHECK(source_list->empty());
  93. *sources = GetFileSystemSources(data);
  94. if (sources->empty()) {
  95. // Not a file system data.
  96. return;
  97. }
  98. // Split sources into a list.
  99. *source_list = base::SplitStringPiece(*sources, u"\n", base::TRIM_WHITESPACE,
  100. base::SPLIT_WANT_NONEMPTY);
  101. }
  102. size_t GetCountOfCopiedFiles(const ui::ClipboardData& data) {
  103. std::u16string sources;
  104. std::vector<base::StringPiece16> source_list;
  105. GetSplitFileSystemData(data, &source_list, &sources);
  106. if (sources.empty()) {
  107. // Not a file system data.
  108. return 0;
  109. }
  110. return source_list.size();
  111. }
  112. std::u16string GetFileSystemSources(const ui::ClipboardData& data) {
  113. // Outside of the Files app, file system sources are written as filenames.
  114. if (ContainsFormat(data, ui::ClipboardInternalFormat::kFilenames)) {
  115. std::vector<std::string> sources;
  116. for (const ui::FileInfo& filename : data.filenames())
  117. sources.push_back(filename.path.value());
  118. return base::UTF8ToUTF16(base::JoinString(sources, "\n"));
  119. }
  120. // Within the Files app, file system sources are written as custom data.
  121. if (!ContainsFormat(data, ui::ClipboardInternalFormat::kCustom))
  122. return std::u16string();
  123. // Attempt to read file system sources in the custom data.
  124. std::u16string sources;
  125. ui::ReadCustomDataForType(data.custom_data_data().c_str(),
  126. data.custom_data_data().size(),
  127. kFileSystemSourcesType, &sources);
  128. return sources;
  129. }
  130. bool IsSupported(const ui::ClipboardData& data) {
  131. const absl::optional<ui::ClipboardInternalFormat> format =
  132. CalculateMainFormat(data);
  133. // Empty `data` is not supported.
  134. if (!format.has_value())
  135. return false;
  136. // The only supported type of custom data is file system data.
  137. if (format.value() == ui::ClipboardInternalFormat::kCustom)
  138. return ContainsFileSystemData(data);
  139. return true;
  140. }
  141. bool IsEnabledInCurrentMode() {
  142. const auto* session_controller = Shell::Get()->session_controller();
  143. // The clipboard history menu is enabled only when a user has logged in and
  144. // login UI is hidden.
  145. if (session_controller->GetSessionState() !=
  146. session_manager::SessionState::ACTIVE) {
  147. return false;
  148. }
  149. switch (session_controller->login_status()) {
  150. case LoginStatus::NOT_LOGGED_IN:
  151. case LoginStatus::LOCKED:
  152. case LoginStatus::KIOSK_APP:
  153. case LoginStatus::PUBLIC:
  154. return false;
  155. case LoginStatus::USER:
  156. case LoginStatus::GUEST:
  157. case LoginStatus::CHILD:
  158. return true;
  159. }
  160. }
  161. gfx::ImageSkia GetIconForFileClipboardItem(const ClipboardHistoryItem& item,
  162. const std::string& file_name) {
  163. DCHECK_EQ(ClipboardHistoryDisplayFormat::kFile,
  164. CalculateDisplayFormat(item.data()));
  165. const int copied_files_count = GetCountOfCopiedFiles(item.data());
  166. if (copied_files_count == 0)
  167. return gfx::ImageSkia();
  168. if (copied_files_count == 1) {
  169. return chromeos::GetIconForPath(
  170. base::FilePath(file_name),
  171. ash::DarkLightModeControllerImpl::Get()->IsDarkModeEnabled());
  172. }
  173. constexpr std::array<const gfx::VectorIcon*, 9> icons = {
  174. &kTwoFilesIcon, &kThreeFilesIcon, &kFourFilesIcon,
  175. &kFiveFilesIcon, &kSixFilesIcon, &kSevenFilesIcon,
  176. &kEightFilesIcon, &kNineFilesIcon, &kMoreThanNineFilesIcon};
  177. int icon_index = std::min(copied_files_count - 2, (int)icons.size() - 1);
  178. const SkColor icon_color = ash::AshColorProvider::Get()->GetContentLayerColor(
  179. AshColorProvider::ContentLayerType::kIconColorPrimary);
  180. return CreateVectorIcon(*icons[icon_index], icon_color);
  181. }
  182. } // namespace ClipboardHistoryUtil
  183. } // namespace ash