| OLD | NEW |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ui/base/x/selection_utils.h" | 5 #include "ui/base/x/selection_utils.h" |
| 6 | 6 |
| 7 #include <set> | 7 #include <set> |
| 8 | 8 |
| 9 #include "base/i18n/icu_string_conversions.h" | 9 #include "base/i18n/icu_string_conversions.h" |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 51 for (std::vector< ::Atom>::const_iterator jt = two.begin(); jt != two.end(); | 51 for (std::vector< ::Atom>::const_iterator jt = two.begin(); jt != two.end(); |
| 52 ++jt) { | 52 ++jt) { |
| 53 if (*it == *jt) { | 53 if (*it == *jt) { |
| 54 output->push_back(*it); | 54 output->push_back(*it); |
| 55 break; | 55 break; |
| 56 } | 56 } |
| 57 } | 57 } |
| 58 } | 58 } |
| 59 } | 59 } |
| 60 | 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) { |
| 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) { |
| 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 |
| 61 /////////////////////////////////////////////////////////////////////////////// | 98 /////////////////////////////////////////////////////////////////////////////// |
| 62 | 99 |
| 63 SelectionFormatMap::SelectionFormatMap() {} | 100 SelectionFormatMap::SelectionFormatMap() {} |
| 64 | 101 |
| 65 SelectionFormatMap::~SelectionFormatMap() { | 102 SelectionFormatMap::~SelectionFormatMap() {} |
| 66 // WriteText() inserts the same pointer multiple times for different | |
| 67 // representations; we need to dedupe it. | |
| 68 std::set<char*> to_delete; | |
| 69 for (InternalMap::iterator it = data_.begin(); it != data_.end(); ++it) | |
| 70 to_delete.insert(it->second.first); | |
| 71 | 103 |
| 72 for (std::set<char*>::iterator it = to_delete.begin(); it != to_delete.end(); | 104 void SelectionFormatMap::Insert( |
| 73 ++it) { | 105 ::Atom atom, |
| 74 delete [] *it; | 106 const scoped_refptr<base::RefCountedMemory>& item) { |
| 75 } | 107 data_.insert(std::make_pair(atom, item)); |
| 76 } | 108 } |
| 77 | 109 |
| 78 void SelectionFormatMap::Insert(::Atom atom, char* data, size_t size) { | 110 ui::SelectionData SelectionFormatMap::GetFirstOf( |
| 79 // Views code often inserts the same content multiple times, so we have to | |
| 80 // free old data. Only call delete when it's the last pointer we have to that | |
| 81 // data. | |
| 82 InternalMap::iterator exists_it = data_.find(atom); | |
| 83 if (exists_it != data_.end()) { | |
| 84 int count = 0; | |
| 85 for (InternalMap::iterator it = data_.begin(); it != data_.end(); ++it) { | |
| 86 if (it->second.first == exists_it->second.first) | |
| 87 count++; | |
| 88 } | |
| 89 | |
| 90 if (count == 1) | |
| 91 delete [] exists_it->second.first; | |
| 92 } | |
| 93 | |
| 94 data_.insert(std::make_pair(atom, std::make_pair(data, size))); | |
| 95 } | |
| 96 | |
| 97 ui::SelectionData* SelectionFormatMap::GetFirstOf( | |
| 98 const std::vector< ::Atom>& requested_types) const { | 111 const std::vector< ::Atom>& requested_types) const { |
| 99 for (std::vector< ::Atom>::const_iterator it = requested_types.begin(); | 112 for (std::vector< ::Atom>::const_iterator it = requested_types.begin(); |
| 100 it != requested_types.end(); ++it) { | 113 it != requested_types.end(); ++it) { |
| 101 const_iterator data_it = data_.find(*it); | 114 const_iterator data_it = data_.find(*it); |
| 102 if (data_it != data_.end()) { | 115 if (data_it != data_.end()) { |
| 103 ui::SelectionData* data = new SelectionData; | 116 return SelectionData(data_it->first, data_it->second); |
| 104 data->Set(data_it->first, data_it->second.first, data_it->second.second, | |
| 105 false); | |
| 106 return data; | |
| 107 } | 117 } |
| 108 } | 118 } |
| 109 | 119 |
| 110 return NULL; | 120 return SelectionData(); |
| 111 } | 121 } |
| 112 | 122 |
| 113 std::vector< ::Atom> SelectionFormatMap::GetTypes() const { | 123 std::vector< ::Atom> SelectionFormatMap::GetTypes() const { |
| 114 std::vector< ::Atom> atoms; | 124 std::vector< ::Atom> atoms; |
| 115 for (const_iterator it = data_.begin(); it != data_.end(); ++it) | 125 for (const_iterator it = data_.begin(); it != data_.end(); ++it) |
| 116 atoms.push_back(it->first); | 126 atoms.push_back(it->first); |
| 117 | 127 |
| 118 return atoms; | 128 return atoms; |
| 119 } | 129 } |
| 120 | 130 |
| 121 scoped_ptr<SelectionFormatMap> SelectionFormatMap::Clone() const { | |
| 122 scoped_ptr<SelectionFormatMap> ret(new SelectionFormatMap); | |
| 123 | |
| 124 for (const_iterator it = data_.begin(); it != data_.end(); ++it) { | |
| 125 char* data_copy = new char[it->second.second]; | |
| 126 memcpy(data_copy, it->second.first, it->second.second); | |
| 127 ret->Insert(it->first, data_copy, it->second.second); | |
| 128 } | |
| 129 | |
| 130 return ret.Pass(); | |
| 131 } | |
| 132 | |
| 133 /////////////////////////////////////////////////////////////////////////////// | 131 /////////////////////////////////////////////////////////////////////////////// |
| 134 | 132 |
| 135 SelectionData::SelectionData() | 133 SelectionData::SelectionData() |
| 136 : type_(None), | 134 : type_(None), |
| 137 data_(NULL), | |
| 138 size_(0), | |
| 139 owned_(false), | |
| 140 atom_cache_(ui::GetXDisplay(), kSelectionDataAtoms) { | 135 atom_cache_(ui::GetXDisplay(), kSelectionDataAtoms) { |
| 141 } | 136 } |
| 142 | 137 |
| 143 SelectionData::~SelectionData() { | 138 SelectionData::SelectionData( |
| 144 if (owned_) | 139 ::Atom type, |
| 145 XFree(data_); | 140 const scoped_refptr<base::RefCountedMemory>& memory) |
| 141 : type_(type), |
| 142 memory_(memory), |
| 143 atom_cache_(ui::GetXDisplay(), kSelectionDataAtoms) { |
| 146 } | 144 } |
| 147 | 145 |
| 148 void SelectionData::Set(::Atom type, char* data, size_t size, bool owned) { | 146 SelectionData::SelectionData(const SelectionData& rhs) |
| 149 if (owned_) | 147 : type_(rhs.type_), |
| 150 XFree(data_); | 148 memory_(rhs.memory_), |
| 149 atom_cache_(ui::GetXDisplay(), kSelectionDataAtoms) { |
| 150 } |
| 151 | 151 |
| 152 type_ = type; | 152 SelectionData::~SelectionData() {} |
| 153 data_ = data; | 153 |
| 154 size_ = size; | 154 SelectionData& SelectionData::operator=(const SelectionData& rhs) { |
| 155 owned_ = owned; | 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_ ? memory_->front() : NULL; |
| 172 } |
| 173 |
| 174 size_t SelectionData::GetSize() const { |
| 175 return memory_ ? memory_->size() : 0; |
| 156 } | 176 } |
| 157 | 177 |
| 158 std::string SelectionData::GetText() const { | 178 std::string SelectionData::GetText() const { |
| 159 if (type_ == atom_cache_.GetAtom(kUtf8String) || | 179 if (type_ == atom_cache_.GetAtom(kUtf8String) || |
| 160 type_ == atom_cache_.GetAtom(kText)) { | 180 type_ == atom_cache_.GetAtom(kText)) { |
| 161 return std::string(data_, size_); | 181 return RefCountedMemoryToString(memory_); |
| 162 } else if (type_ == atom_cache_.GetAtom(kString)) { | 182 } else if (type_ == atom_cache_.GetAtom(kString)) { |
| 163 std::string result; | 183 std::string result; |
| 164 base::ConvertToUtf8AndNormalize(std::string(data_, size_), | 184 base::ConvertToUtf8AndNormalize(RefCountedMemoryToString(memory_), |
| 165 base::kCodepageLatin1, | 185 base::kCodepageLatin1, |
| 166 &result); | 186 &result); |
| 167 return result; | 187 return result; |
| 168 } else { | 188 } else { |
| 169 // BTW, I looked at COMPOUND_TEXT, and there's no way we're going to | 189 // BTW, I looked at COMPOUND_TEXT, and there's no way we're going to |
| 170 // support that. Yuck. | 190 // support that. Yuck. |
| 171 NOTREACHED(); | 191 NOTREACHED(); |
| 172 return std::string(); | 192 return std::string(); |
| 173 } | 193 } |
| 174 } | 194 } |
| 175 | 195 |
| 176 string16 SelectionData::GetHtml() const { | 196 string16 SelectionData::GetHtml() const { |
| 177 string16 markup; | 197 string16 markup; |
| 178 | 198 |
| 179 if (type_ == atom_cache_.GetAtom(Clipboard::kMimeTypeHTML)) { | 199 if (type_ == atom_cache_.GetAtom(Clipboard::kMimeTypeHTML)) { |
| 200 const unsigned char* data = GetData(); |
| 201 size_t size = GetSize(); |
| 202 |
| 180 // If the data starts with 0xFEFF, i.e., Byte Order Mark, assume it is | 203 // If the data starts with 0xFEFF, i.e., Byte Order Mark, assume it is |
| 181 // UTF-16, otherwise assume UTF-8. | 204 // UTF-16, otherwise assume UTF-8. |
| 182 if (size_ >= 2 && | 205 if (size >= 2 && |
| 183 reinterpret_cast<const uint16_t*>(data_)[0] == 0xFEFF) { | 206 reinterpret_cast<const uint16_t*>(data)[0] == 0xFEFF) { |
| 184 markup.assign(reinterpret_cast<const uint16_t*>(data_) + 1, | 207 markup.assign(reinterpret_cast<const uint16_t*>(data) + 1, |
| 185 (size_ / 2) - 1); | 208 (size / 2) - 1); |
| 186 } else { | 209 } else { |
| 187 UTF8ToUTF16(reinterpret_cast<const char*>(data_), size_, &markup); | 210 UTF8ToUTF16(reinterpret_cast<const char*>(data), size, &markup); |
| 188 } | 211 } |
| 189 | 212 |
| 190 // If there is a terminating NULL, drop it. | 213 // If there is a terminating NULL, drop it. |
| 191 if (!markup.empty() && markup.at(markup.length() - 1) == '\0') | 214 if (!markup.empty() && markup.at(markup.length() - 1) == '\0') |
| 192 markup.resize(markup.length() - 1); | 215 markup.resize(markup.length() - 1); |
| 193 | 216 |
| 194 return markup; | 217 return markup; |
| 195 } else { | 218 } else { |
| 196 NOTREACHED(); | 219 NOTREACHED(); |
| 197 return markup; | 220 return markup; |
| 198 } | 221 } |
| 199 } | 222 } |
| 200 | 223 |
| 201 void SelectionData::AssignTo(std::string* result) const { | 224 void SelectionData::AssignTo(std::string* result) const { |
| 202 result->assign(data_, size_); | 225 *result = RefCountedMemoryToString(memory_); |
| 203 } | 226 } |
| 204 | 227 |
| 205 void SelectionData::AssignTo(string16* result) const { | 228 void SelectionData::AssignTo(string16* result) const { |
| 206 result->assign(reinterpret_cast<base::char16*>(data_), size_ / 2); | 229 *result = RefCountedMemoryToString16(memory_); |
| 207 } | 230 } |
| 208 | 231 |
| 209 } // namespace ui | 232 } // namespace ui |
| OLD | NEW |