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