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