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 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(kUtf8String)); 34 atoms.push_back(atom_cache->GetAtom(kString)); 35 atoms.push_back(atom_cache->GetAtom(kText)); 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>& 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 58 void 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 65 std::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 80 string16 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 97 SelectionFormatMap::SelectionFormatMap() {} 98 99 SelectionFormatMap::~SelectionFormatMap() {} 100 101 void 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 108 ui::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 121 std::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 131 SelectionData::SelectionData() 132 : type_(None), 133 atom_cache_(gfx::GetXDisplay(), kSelectionDataAtoms) { 134 } 135 136 SelectionData::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 144 SelectionData::SelectionData(const SelectionData& rhs) 145 : type_(rhs.type_), 146 memory_(rhs.memory_), 147 atom_cache_(gfx::GetXDisplay(), kSelectionDataAtoms) { 148 } 149 150 SelectionData::~SelectionData() {} 151 152 SelectionData& 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 160 bool SelectionData::IsValid() const { 161 return type_ != None; 162 } 163 164 ::Atom SelectionData::GetType() const { 165 return type_; 166 } 167 168 const unsigned char* SelectionData::GetData() const { 169 return memory_.get() ? memory_->front() : NULL; 170 } 171 172 size_t SelectionData::GetSize() const { 173 return memory_.get() ? memory_->size() : 0; 174 } 175 176 std::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 194 string16 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 222 void SelectionData::AssignTo(std::string* result) const { 223 *result = RefCountedMemoryToString(memory_); 224 } 225 226 void SelectionData::AssignTo(string16* result) const { 227 *result = RefCountedMemoryToString16(memory_); 228 } 229 230 } // namespace ui 231