Add ICU message format support
[chromium-blink-merge.git] / ui / base / x / selection_utils.cc
blobcc9afbed95c55cba29f2d19af07fb36e82a4fd5b
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"
7 #include <set>
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"
18 namespace ui {
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,
29 kString,
30 kText,
31 kTextPlain,
32 kTextPlainUtf8,
33 kUtf8String,
34 NULL
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));
44 return atoms;
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));
51 return atoms;
54 std::vector< ::Atom> GetURIListAtomsFrom(const X11AtomCache* atom_cache) {
55 std::vector< ::Atom> atoms;
56 atoms.push_back(atom_cache->GetAtom(Clipboard::kMimeTypeURIList));
57 return atoms;
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.
81 std::string unparsed;
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) {
89 if (!memory.get()) {
90 NOTREACHED();
91 return std::string();
94 size_t size = memory->size();
95 if (!size)
96 return std::string();
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) {
104 if (!memory.get()) {
105 NOTREACHED();
106 return base::string16();
109 size_t size = memory->size();
110 if (!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(
124 ::Atom atom,
125 const scoped_refptr<base::RefCountedMemory>& item) {
126 data_.erase(atom);
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);
148 return atoms;
151 ///////////////////////////////////////////////////////////////////////////////
153 SelectionData::SelectionData()
154 : type_(None),
155 atom_cache_(gfx::GetXDisplay(), kSelectionDataAtoms) {
158 SelectionData::SelectionData(
159 ::Atom type,
160 const scoped_refptr<base::RefCountedMemory>& memory)
161 : type_(type),
162 memory_(memory),
163 atom_cache_(gfx::GetXDisplay(), kSelectionDataAtoms) {
166 SelectionData::SelectionData(const SelectionData& rhs)
167 : type_(rhs.type_),
168 memory_(rhs.memory_),
169 atom_cache_(gfx::GetXDisplay(), kSelectionDataAtoms) {
172 SelectionData::~SelectionData() {}
174 SelectionData& SelectionData::operator=(const SelectionData& rhs) {
175 type_ = rhs.type_;
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.
179 return *this;
182 bool SelectionData::IsValid() const {
183 return type_ != None;
186 ::Atom SelectionData::GetType() const {
187 return type_;
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)) {
205 std::string result;
206 base::ConvertToUtf8AndNormalize(RefCountedMemoryToString(memory_),
207 base::kCodepageLatin1,
208 &result);
209 return result;
210 } else {
211 // BTW, I looked at COMPOUND_TEXT, and there's no way we're going to
212 // support that. Yuck.
213 NOTREACHED();
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.
227 if (size >= 2 &&
228 reinterpret_cast<const uint16_t*>(data)[0] == 0xFEFF) {
229 markup.assign(reinterpret_cast<const uint16_t*>(data) + 1,
230 (size / 2) - 1);
231 } else {
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);
239 return markup;
240 } else {
241 NOTREACHED();
242 return markup;
246 void SelectionData::AssignTo(std::string* result) const {
247 *result = RefCountedMemoryToString(memory_);
250 void SelectionData::AssignTo(base::string16* result) const {
251 *result = RefCountedMemoryToString16(memory_);
254 } // namespace ui