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
5 #include "ui/base/x/selection_utils.h"
6
7 #include <set>
8
9 #include "base/i18n/icu_string_conversions.h"
10 #include "base/logging.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "ui/base/clipboard/clipboard.h"
13 #include "ui/base/x/x11_util.h"
14 #include "ui/gfx/x/x11_atom_cache.h"
15
16 namespace ui {
17
18 const char kMimeTypeMozillaURL[] = "text/x-moz-url";
19 const char kString[] = "STRING";
20 const char kText[] = "TEXT";
21 const char kUtf8String[] = "UTF8_STRING";
22
23 const char* kSelectionDataAtoms[] = {
24 Clipboard::kMimeTypeHTML,
25 kString,
26 kText,
27 kUtf8String,
28 NULL
29 };
30
GetTextAtomsFrom(const X11AtomCache * atom_cache)31 std::vector< ::Atom> GetTextAtomsFrom(const X11AtomCache* atom_cache) {
32 std::vector< ::Atom> atoms;
33 atoms.push_back(atom_cache->GetAtom(kUtf8String));
34 atoms.push_back(atom_cache->GetAtom(kString));
35 atoms.push_back(atom_cache->GetAtom(kText));
36 return atoms;
37 }
38
GetURLAtomsFrom(const X11AtomCache * atom_cache)39 std::vector< ::Atom> GetURLAtomsFrom(const X11AtomCache* atom_cache) {
40 std::vector< ::Atom> atoms;
41 atoms.push_back(atom_cache->GetAtom(Clipboard::kMimeTypeURIList));
42 atoms.push_back(atom_cache->GetAtom(kMimeTypeMozillaURL));
43 return atoms;
44 }
45
GetAtomIntersection(const std::vector<::Atom> & desired,const std::vector<::Atom> & offered,std::vector<::Atom> * output)46 void GetAtomIntersection(const std::vector< ::Atom>& desired,
47 const std::vector< ::Atom>& offered,
48 std::vector< ::Atom>* output) {
49 for (std::vector< ::Atom>::const_iterator it = desired.begin();
50 it != desired.end(); ++it) {
51 std::vector< ::Atom>::const_iterator jt =
52 std::find(offered.begin(), offered.end(), *it);
53 if (jt != offered.end())
54 output->push_back(*it);
55 }
56 }
57
AddString16ToVector(const string16 & str,std::vector<unsigned char> * bytes)58 void AddString16ToVector(const string16& str,
59 std::vector<unsigned char>* bytes) {
60 const unsigned char* front =
61 reinterpret_cast<const unsigned char*>(str.data());
62 bytes->insert(bytes->end(), front, front + (str.size() * 2));
63 }
64
RefCountedMemoryToString(const scoped_refptr<base::RefCountedMemory> & memory)65 std::string RefCountedMemoryToString(
66 const scoped_refptr<base::RefCountedMemory>& memory) {
67 if (!memory.get()) {
68 NOTREACHED();
69 return std::string();
70 }
71
72 size_t size = memory->size();
73 if (!size)
74 return std::string();
75
76 const unsigned char* front = memory->front();
77 return std::string(reinterpret_cast<const char*>(front), size);
78 }
79
RefCountedMemoryToString16(const scoped_refptr<base::RefCountedMemory> & memory)80 string16 RefCountedMemoryToString16(
81 const scoped_refptr<base::RefCountedMemory>& memory) {
82 if (!memory.get()) {
83 NOTREACHED();
84 return string16();
85 }
86
87 size_t size = memory->size();
88 if (!size)
89 return string16();
90
91 const unsigned char* front = memory->front();
92 return string16(reinterpret_cast<const base::char16*>(front), size / 2);
93 }
94
95 ///////////////////////////////////////////////////////////////////////////////
96
SelectionFormatMap()97 SelectionFormatMap::SelectionFormatMap() {}
98
~SelectionFormatMap()99 SelectionFormatMap::~SelectionFormatMap() {}
100
Insert(::Atom atom,const scoped_refptr<base::RefCountedMemory> & item)101 void SelectionFormatMap::Insert(
102 ::Atom atom,
103 const scoped_refptr<base::RefCountedMemory>& item) {
104 data_.erase(atom);
105 data_.insert(std::make_pair(atom, item));
106 }
107
GetFirstOf(const std::vector<::Atom> & requested_types) const108 ui::SelectionData SelectionFormatMap::GetFirstOf(
109 const std::vector< ::Atom>& requested_types) const {
110 for (std::vector< ::Atom>::const_iterator it = requested_types.begin();
111 it != requested_types.end(); ++it) {
112 const_iterator data_it = data_.find(*it);
113 if (data_it != data_.end()) {
114 return SelectionData(data_it->first, data_it->second);
115 }
116 }
117
118 return SelectionData();
119 }
120
GetTypes() const121 std::vector< ::Atom> SelectionFormatMap::GetTypes() const {
122 std::vector< ::Atom> atoms;
123 for (const_iterator it = data_.begin(); it != data_.end(); ++it)
124 atoms.push_back(it->first);
125
126 return atoms;
127 }
128
129 ///////////////////////////////////////////////////////////////////////////////
130
SelectionData()131 SelectionData::SelectionData()
132 : type_(None),
133 atom_cache_(gfx::GetXDisplay(), kSelectionDataAtoms) {
134 }
135
SelectionData(::Atom type,const scoped_refptr<base::RefCountedMemory> & memory)136 SelectionData::SelectionData(
137 ::Atom type,
138 const scoped_refptr<base::RefCountedMemory>& memory)
139 : type_(type),
140 memory_(memory),
141 atom_cache_(gfx::GetXDisplay(), kSelectionDataAtoms) {
142 }
143
SelectionData(const SelectionData & rhs)144 SelectionData::SelectionData(const SelectionData& rhs)
145 : type_(rhs.type_),
146 memory_(rhs.memory_),
147 atom_cache_(gfx::GetXDisplay(), kSelectionDataAtoms) {
148 }
149
~SelectionData()150 SelectionData::~SelectionData() {}
151
operator =(const SelectionData & rhs)152 SelectionData& SelectionData::operator=(const SelectionData& rhs) {
153 type_ = rhs.type_;
154 memory_ = rhs.memory_;
155 // TODO(erg): In some future where we have to support multiple X Displays,
156 // the following will also need to deal with the display.
157 return *this;
158 }
159
IsValid() const160 bool SelectionData::IsValid() const {
161 return type_ != None;
162 }
163
GetType() const164 ::Atom SelectionData::GetType() const {
165 return type_;
166 }
167
GetData() const168 const unsigned char* SelectionData::GetData() const {
169 return memory_.get() ? memory_->front() : NULL;
170 }
171
GetSize() const172 size_t SelectionData::GetSize() const {
173 return memory_.get() ? memory_->size() : 0;
174 }
175
GetText() const176 std::string SelectionData::GetText() const {
177 if (type_ == atom_cache_.GetAtom(kUtf8String) ||
178 type_ == atom_cache_.GetAtom(kText)) {
179 return RefCountedMemoryToString(memory_);
180 } else if (type_ == atom_cache_.GetAtom(kString)) {
181 std::string result;
182 base::ConvertToUtf8AndNormalize(RefCountedMemoryToString(memory_),
183 base::kCodepageLatin1,
184 &result);
185 return result;
186 } else {
187 // BTW, I looked at COMPOUND_TEXT, and there's no way we're going to
188 // support that. Yuck.
189 NOTREACHED();
190 return std::string();
191 }
192 }
193
GetHtml() const194 string16 SelectionData::GetHtml() const {
195 string16 markup;
196
197 if (type_ == atom_cache_.GetAtom(Clipboard::kMimeTypeHTML)) {
198 const unsigned char* data = GetData();
199 size_t size = GetSize();
200
201 // If the data starts with 0xFEFF, i.e., Byte Order Mark, assume it is
202 // UTF-16, otherwise assume UTF-8.
203 if (size >= 2 &&
204 reinterpret_cast<const uint16_t*>(data)[0] == 0xFEFF) {
205 markup.assign(reinterpret_cast<const uint16_t*>(data) + 1,
206 (size / 2) - 1);
207 } else {
208 UTF8ToUTF16(reinterpret_cast<const char*>(data), size, &markup);
209 }
210
211 // If there is a terminating NULL, drop it.
212 if (!markup.empty() && markup.at(markup.length() - 1) == '\0')
213 markup.resize(markup.length() - 1);
214
215 return markup;
216 } else {
217 NOTREACHED();
218 return markup;
219 }
220 }
221
AssignTo(std::string * result) const222 void SelectionData::AssignTo(std::string* result) const {
223 *result = RefCountedMemoryToString(memory_);
224 }
225
AssignTo(string16 * result) const226 void SelectionData::AssignTo(string16* result) const {
227 *result = RefCountedMemoryToString16(memory_);
228 }
229
230 } // namespace ui
231