selection_utils.cc 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. // Copyright (c) 2013 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 "ui/base/x/selection_utils.h"
  5. #include <stdint.h>
  6. #include <set>
  7. #include "base/containers/contains.h"
  8. #include "base/i18n/icu_string_conversions.h"
  9. #include "base/memory/ref_counted_memory.h"
  10. #include "base/memory/scoped_refptr.h"
  11. #include "base/notreached.h"
  12. #include "base/strings/string_split.h"
  13. #include "base/strings/string_util.h"
  14. #include "base/strings/utf_string_conversions.h"
  15. #include "ui/base/clipboard/clipboard_constants.h"
  16. #include "ui/gfx/x/x11_atom_cache.h"
  17. namespace ui {
  18. std::vector<x11::Atom> GetTextAtomsFrom() {
  19. static const std::vector<x11::Atom> atoms = {
  20. x11::GetAtom(kMimeTypeLinuxUtf8String),
  21. x11::GetAtom(kMimeTypeLinuxString), x11::GetAtom(kMimeTypeLinuxText),
  22. x11::GetAtom(kMimeTypeText), x11::GetAtom(kMimeTypeTextUtf8)};
  23. return atoms;
  24. }
  25. std::vector<x11::Atom> GetURLAtomsFrom() {
  26. static const std::vector<x11::Atom> atoms = {
  27. x11::GetAtom(kMimeTypeURIList), x11::GetAtom(kMimeTypeMozillaURL)};
  28. return atoms;
  29. }
  30. std::vector<x11::Atom> GetURIListAtomsFrom() {
  31. static const std::vector<x11::Atom> atoms = {x11::GetAtom(kMimeTypeURIList)};
  32. return atoms;
  33. }
  34. void GetAtomIntersection(const std::vector<x11::Atom>& desired,
  35. const std::vector<x11::Atom>& offered,
  36. std::vector<x11::Atom>* output) {
  37. for (const auto& desired_atom : desired) {
  38. if (base::Contains(offered, desired_atom))
  39. output->push_back(desired_atom);
  40. }
  41. }
  42. void AddString16ToVector(const std::u16string& str,
  43. std::vector<unsigned char>* bytes) {
  44. const unsigned char* front =
  45. reinterpret_cast<const unsigned char*>(str.data());
  46. bytes->insert(bytes->end(), front, front + (str.size() * 2));
  47. }
  48. std::vector<std::string> ParseURIList(const SelectionData& data) {
  49. // uri-lists are newline separated file lists in URL encoding.
  50. std::string unparsed;
  51. data.AssignTo(&unparsed);
  52. return base::SplitString(unparsed, "\n", base::KEEP_WHITESPACE,
  53. base::SPLIT_WANT_NONEMPTY);
  54. }
  55. std::string RefCountedMemoryToString(
  56. const scoped_refptr<base::RefCountedMemory>& memory) {
  57. if (!memory.get()) {
  58. NOTREACHED();
  59. return std::string();
  60. }
  61. size_t size = memory->size();
  62. if (!size)
  63. return std::string();
  64. const unsigned char* front = memory->front();
  65. return std::string(reinterpret_cast<const char*>(front), size);
  66. }
  67. std::u16string RefCountedMemoryToString16(
  68. const scoped_refptr<base::RefCountedMemory>& memory) {
  69. if (!memory.get()) {
  70. NOTREACHED();
  71. return std::u16string();
  72. }
  73. size_t size = memory->size();
  74. if (!size)
  75. return std::u16string();
  76. const unsigned char* front = memory->front();
  77. return std::u16string(reinterpret_cast<const char16_t*>(front), size / 2);
  78. }
  79. ///////////////////////////////////////////////////////////////////////////////
  80. SelectionFormatMap::SelectionFormatMap() = default;
  81. SelectionFormatMap::SelectionFormatMap(const SelectionFormatMap& other) =
  82. default;
  83. SelectionFormatMap::~SelectionFormatMap() = default;
  84. void SelectionFormatMap::Insert(
  85. x11::Atom atom,
  86. const scoped_refptr<base::RefCountedMemory>& item) {
  87. data_.erase(atom);
  88. data_.emplace(atom, item);
  89. }
  90. ui::SelectionData SelectionFormatMap::GetFirstOf(
  91. const std::vector<x11::Atom>& requested_types) const {
  92. for (const auto& requested_type : requested_types) {
  93. auto data_it = data_.find(requested_type);
  94. if (data_it != data_.end()) {
  95. return SelectionData(data_it->first, data_it->second);
  96. }
  97. }
  98. return SelectionData();
  99. }
  100. std::vector<x11::Atom> SelectionFormatMap::GetTypes() const {
  101. std::vector<x11::Atom> atoms;
  102. for (const auto& datum : data_)
  103. atoms.push_back(datum.first);
  104. return atoms;
  105. }
  106. ///////////////////////////////////////////////////////////////////////////////
  107. SelectionData::SelectionData() : type_(x11::Atom::None) {}
  108. SelectionData::SelectionData(
  109. x11::Atom type,
  110. const scoped_refptr<base::RefCountedMemory>& memory)
  111. : type_(type), memory_(memory) {}
  112. SelectionData::SelectionData(const SelectionData& rhs) = default;
  113. SelectionData::~SelectionData() = default;
  114. SelectionData& SelectionData::operator=(const SelectionData& rhs) {
  115. type_ = rhs.type_;
  116. memory_ = rhs.memory_;
  117. // TODO(erg): In some future where we have to support multiple X Displays,
  118. // the following will also need to deal with the display.
  119. return *this;
  120. }
  121. bool SelectionData::IsValid() const {
  122. return type_ != x11::Atom::None;
  123. }
  124. x11::Atom SelectionData::GetType() const {
  125. return type_;
  126. }
  127. const unsigned char* SelectionData::GetData() const {
  128. return memory_.get() ? memory_->front() : nullptr;
  129. }
  130. size_t SelectionData::GetSize() const {
  131. return memory_.get() ? memory_->size() : 0;
  132. }
  133. std::string SelectionData::GetText() const {
  134. if (type_ == x11::GetAtom(kMimeTypeLinuxUtf8String) ||
  135. type_ == x11::GetAtom(kMimeTypeLinuxText) ||
  136. type_ == x11::GetAtom(kMimeTypeTextUtf8)) {
  137. return RefCountedMemoryToString(memory_);
  138. } else if (type_ == x11::GetAtom(kMimeTypeLinuxString) ||
  139. type_ == x11::GetAtom(kMimeTypeText)) {
  140. std::string result;
  141. base::ConvertToUtf8AndNormalize(RefCountedMemoryToString(memory_),
  142. base::kCodepageLatin1, &result);
  143. return result;
  144. } else {
  145. // BTW, I looked at COMPOUND_TEXT, and there's no way we're going to
  146. // support that. Yuck.
  147. NOTREACHED();
  148. return std::string();
  149. }
  150. }
  151. std::u16string SelectionData::GetHtml() const {
  152. std::u16string markup;
  153. if (type_ == x11::GetAtom(kMimeTypeHTML)) {
  154. const unsigned char* data = GetData();
  155. size_t size = GetSize();
  156. // If the data starts with U+FEFF, i.e., Byte Order Mark, assume it is
  157. // UTF-16, otherwise assume UTF-8.
  158. if (size >= 2 && reinterpret_cast<const char16_t*>(data)[0] == u'\uFEFF') {
  159. markup.assign(reinterpret_cast<const char16_t*>(data) + 1,
  160. (size / 2) - 1);
  161. } else {
  162. base::UTF8ToUTF16(reinterpret_cast<const char*>(data), size, &markup);
  163. }
  164. // If there is a terminating NULL, drop it.
  165. if (!markup.empty() && markup.at(markup.length() - 1) == '\0')
  166. markup.resize(markup.length() - 1);
  167. return markup;
  168. } else {
  169. NOTREACHED();
  170. return markup;
  171. }
  172. }
  173. void SelectionData::AssignTo(std::string* result) const {
  174. *result = RefCountedMemoryToString(memory_);
  175. }
  176. void SelectionData::AssignTo(std::u16string* result) const {
  177. *result = RefCountedMemoryToString16(memory_);
  178. }
  179. scoped_refptr<base::RefCountedBytes> SelectionData::TakeBytes() {
  180. if (!memory_.get())
  181. return nullptr;
  182. auto* memory = memory_.release();
  183. return base::MakeRefCounted<base::RefCountedBytes>(memory->data(),
  184. memory->size());
  185. }
  186. } // namespace ui