selection_utils.cc revision 4e180b6a0b4720a9b8e9e959a882386f690f08ff
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
16namespace ui {
17
18const char kMimeTypeMozillaURL[] = "text/x-moz-url";
19const char kString[] = "STRING";
20const char kText[] = "TEXT";
21const char kUtf8String[] = "UTF8_STRING";
22
23const char* kSelectionDataAtoms[] = {
24  Clipboard::kMimeTypeHTML,
25  kString,
26  kText,
27  kUtf8String,
28  NULL
29};
30
31std::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
39std::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
46void 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
58void 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
65std::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
80string16 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
97SelectionFormatMap::SelectionFormatMap() {}
98
99SelectionFormatMap::~SelectionFormatMap() {}
100
101void 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
108ui::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
121std::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
131SelectionData::SelectionData()
132    : type_(None),
133      atom_cache_(gfx::GetXDisplay(), kSelectionDataAtoms) {
134}
135
136SelectionData::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
144SelectionData::SelectionData(const SelectionData& rhs)
145    : type_(rhs.type_),
146      memory_(rhs.memory_),
147      atom_cache_(gfx::GetXDisplay(), kSelectionDataAtoms) {
148}
149
150SelectionData::~SelectionData() {}
151
152SelectionData& 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
160bool SelectionData::IsValid() const {
161  return type_ != None;
162}
163
164::Atom SelectionData::GetType() const {
165  return type_;
166}
167
168const unsigned char* SelectionData::GetData() const {
169  return memory_.get() ? memory_->front() : NULL;
170}
171
172size_t SelectionData::GetSize() const {
173  return memory_.get() ? memory_->size() : 0;
174}
175
176std::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
194string16 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
222void SelectionData::AssignTo(std::string* result) const {
223  *result = RefCountedMemoryToString(memory_);
224}
225
226void SelectionData::AssignTo(string16* result) const {
227  *result = RefCountedMemoryToString16(memory_);
228}
229
230}  // namespace ui
231