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.
5 #include "ui/base/x/selection_utils.h"
9 #include "base/i18n/icu_string_conversions.h"
10 #include "base/logging.h"
11 #include "base/strings/string_split.h"
12 #include "base/strings/string_util.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "ui/base/clipboard/clipboard.h"
15 #include "ui/base/x/x11_util.h"
16 #include "ui/gfx/x/x11_atom_cache.h"
20 const char kMimeTypeMozillaURL
[] = "text/x-moz-url";
21 const char kString
[] = "STRING";
22 const char kText
[] = "TEXT";
23 const char kTextPlain
[] = "text/plain";
24 const char kTextPlainUtf8
[] = "text/plain;charset=utf-8";
25 const char kUtf8String
[] = "UTF8_STRING";
27 const char* kSelectionDataAtoms
[] = {
28 Clipboard::kMimeTypeHTML
,
37 std::vector
< ::Atom
> GetTextAtomsFrom(const X11AtomCache
* atom_cache
) {
38 std::vector
< ::Atom
> atoms
;
39 atoms
.push_back(atom_cache
->GetAtom(kUtf8String
));
40 atoms
.push_back(atom_cache
->GetAtom(kString
));
41 atoms
.push_back(atom_cache
->GetAtom(kText
));
42 atoms
.push_back(atom_cache
->GetAtom(kTextPlain
));
43 atoms
.push_back(atom_cache
->GetAtom(kTextPlainUtf8
));
47 std::vector
< ::Atom
> GetURLAtomsFrom(const X11AtomCache
* atom_cache
) {
48 std::vector
< ::Atom
> atoms
;
49 atoms
.push_back(atom_cache
->GetAtom(Clipboard::kMimeTypeURIList
));
50 atoms
.push_back(atom_cache
->GetAtom(kMimeTypeMozillaURL
));
54 std::vector
< ::Atom
> GetURIListAtomsFrom(const X11AtomCache
* atom_cache
) {
55 std::vector
< ::Atom
> atoms
;
56 atoms
.push_back(atom_cache
->GetAtom(Clipboard::kMimeTypeURIList
));
60 void GetAtomIntersection(const std::vector
< ::Atom
>& desired
,
61 const std::vector
< ::Atom
>& offered
,
62 std::vector
< ::Atom
>* output
) {
63 for (std::vector
< ::Atom
>::const_iterator it
= desired
.begin();
64 it
!= desired
.end(); ++it
) {
65 std::vector
< ::Atom
>::const_iterator jt
=
66 std::find(offered
.begin(), offered
.end(), *it
);
67 if (jt
!= offered
.end())
68 output
->push_back(*it
);
72 void AddString16ToVector(const base::string16
& str
,
73 std::vector
<unsigned char>* bytes
) {
74 const unsigned char* front
=
75 reinterpret_cast<const unsigned char*>(str
.data());
76 bytes
->insert(bytes
->end(), front
, front
+ (str
.size() * 2));
79 std::vector
<std::string
> ParseURIList(const SelectionData
& data
) {
80 // uri-lists are newline separated file lists in URL encoding.
82 data
.AssignTo(&unparsed
);
83 return base::SplitString(
84 unparsed
, "\n", base::KEEP_WHITESPACE
, base::SPLIT_WANT_NONEMPTY
);
87 std::string
RefCountedMemoryToString(
88 const scoped_refptr
<base::RefCountedMemory
>& memory
) {
94 size_t size
= memory
->size();
98 const unsigned char* front
= memory
->front();
99 return std::string(reinterpret_cast<const char*>(front
), size
);
102 base::string16
RefCountedMemoryToString16(
103 const scoped_refptr
<base::RefCountedMemory
>& memory
) {
106 return base::string16();
109 size_t size
= memory
->size();
111 return base::string16();
113 const unsigned char* front
= memory
->front();
114 return base::string16(reinterpret_cast<const base::char16
*>(front
), size
/ 2);
117 ///////////////////////////////////////////////////////////////////////////////
119 SelectionFormatMap::SelectionFormatMap() {}
121 SelectionFormatMap::~SelectionFormatMap() {}
123 void SelectionFormatMap::Insert(
125 const scoped_refptr
<base::RefCountedMemory
>& item
) {
127 data_
.insert(std::make_pair(atom
, item
));
130 ui::SelectionData
SelectionFormatMap::GetFirstOf(
131 const std::vector
< ::Atom
>& requested_types
) const {
132 for (std::vector
< ::Atom
>::const_iterator it
= requested_types
.begin();
133 it
!= requested_types
.end(); ++it
) {
134 const_iterator data_it
= data_
.find(*it
);
135 if (data_it
!= data_
.end()) {
136 return SelectionData(data_it
->first
, data_it
->second
);
140 return SelectionData();
143 std::vector
< ::Atom
> SelectionFormatMap::GetTypes() const {
144 std::vector
< ::Atom
> atoms
;
145 for (const_iterator it
= data_
.begin(); it
!= data_
.end(); ++it
)
146 atoms
.push_back(it
->first
);
151 ///////////////////////////////////////////////////////////////////////////////
153 SelectionData::SelectionData()
155 atom_cache_(gfx::GetXDisplay(), kSelectionDataAtoms
) {
158 SelectionData::SelectionData(
160 const scoped_refptr
<base::RefCountedMemory
>& memory
)
163 atom_cache_(gfx::GetXDisplay(), kSelectionDataAtoms
) {
166 SelectionData::SelectionData(const SelectionData
& rhs
)
168 memory_(rhs
.memory_
),
169 atom_cache_(gfx::GetXDisplay(), kSelectionDataAtoms
) {
172 SelectionData::~SelectionData() {}
174 SelectionData
& SelectionData::operator=(const SelectionData
& rhs
) {
176 memory_
= rhs
.memory_
;
177 // TODO(erg): In some future where we have to support multiple X Displays,
178 // the following will also need to deal with the display.
182 bool SelectionData::IsValid() const {
183 return type_
!= None
;
186 ::Atom
SelectionData::GetType() const {
190 const unsigned char* SelectionData::GetData() const {
191 return memory_
.get() ? memory_
->front() : NULL
;
194 size_t SelectionData::GetSize() const {
195 return memory_
.get() ? memory_
->size() : 0;
198 std::string
SelectionData::GetText() const {
199 if (type_
== atom_cache_
.GetAtom(kUtf8String
) ||
200 type_
== atom_cache_
.GetAtom(kText
) ||
201 type_
== atom_cache_
.GetAtom(kTextPlainUtf8
)) {
202 return RefCountedMemoryToString(memory_
);
203 } else if (type_
== atom_cache_
.GetAtom(kString
) ||
204 type_
== atom_cache_
.GetAtom(kTextPlain
)) {
206 base::ConvertToUtf8AndNormalize(RefCountedMemoryToString(memory_
),
207 base::kCodepageLatin1
,
211 // BTW, I looked at COMPOUND_TEXT, and there's no way we're going to
212 // support that. Yuck.
214 return std::string();
218 base::string16
SelectionData::GetHtml() const {
219 base::string16 markup
;
221 if (type_
== atom_cache_
.GetAtom(Clipboard::kMimeTypeHTML
)) {
222 const unsigned char* data
= GetData();
223 size_t size
= GetSize();
225 // If the data starts with 0xFEFF, i.e., Byte Order Mark, assume it is
226 // UTF-16, otherwise assume UTF-8.
228 reinterpret_cast<const uint16_t*>(data
)[0] == 0xFEFF) {
229 markup
.assign(reinterpret_cast<const uint16_t*>(data
) + 1,
232 base::UTF8ToUTF16(reinterpret_cast<const char*>(data
), size
, &markup
);
235 // If there is a terminating NULL, drop it.
236 if (!markup
.empty() && markup
.at(markup
.length() - 1) == '\0')
237 markup
.resize(markup
.length() - 1);
246 void SelectionData::AssignTo(std::string
* result
) const {
247 *result
= RefCountedMemoryToString(memory_
);
250 void SelectionData::AssignTo(base::string16
* result
) const {
251 *result
= RefCountedMemoryToString16(memory_
);