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