Chromium Code Reviews| 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 NOTREACHED(); | |
|
sky
2013/06/24 20:36:18
Is an empty string not legal?
Elliot Glaysher
2013/06/24 20:54:35
I want to say that it's impossible, but I'm not ac
| |
| 78 return std::string(); | |
| 79 } | |
| 80 | |
| 81 const unsigned char* front = memory->front(); | |
| 82 return std::string(reinterpret_cast<const char*>(front), size); | |
| 83 } | |
| 84 | |
| 85 string16 RefCountedMemoryToString16( | |
| 86 const scoped_refptr<base::RefCountedMemory>& memory) { | |
| 87 if (!memory) { | |
| 88 NOTREACHED(); | |
| 89 return string16(); | |
| 90 } | |
| 91 | |
| 92 size_t size = memory->size(); | |
| 93 if (!size) { | |
| 94 NOTREACHED(); | |
| 95 return string16(); | |
| 96 } | |
| 97 | |
| 98 const unsigned char* front = memory->front(); | |
| 99 return string16(reinterpret_cast<const base::char16*>(front), size / 2); | |
| 100 } | |
| 101 | |
| 61 /////////////////////////////////////////////////////////////////////////////// | 102 /////////////////////////////////////////////////////////////////////////////// |
| 62 | 103 |
| 63 SelectionFormatMap::SelectionFormatMap() {} | 104 SelectionFormatMap::SelectionFormatMap() {} |
| 64 | 105 |
| 65 SelectionFormatMap::~SelectionFormatMap() { | 106 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 | 107 |
| 72 for (std::set<char*>::iterator it = to_delete.begin(); it != to_delete.end(); | 108 void SelectionFormatMap::Insert( |
| 73 ++it) { | 109 ::Atom atom, |
| 74 delete [] *it; | 110 const scoped_refptr<base::RefCountedMemory>& item) { |
| 75 } | 111 data_.insert(std::make_pair(atom, item)); |
| 76 } | 112 } |
| 77 | 113 |
| 78 void SelectionFormatMap::Insert(::Atom atom, char* data, size_t size) { | 114 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 { | 115 const std::vector< ::Atom>& requested_types) const { |
| 99 for (std::vector< ::Atom>::const_iterator it = requested_types.begin(); | 116 for (std::vector< ::Atom>::const_iterator it = requested_types.begin(); |
| 100 it != requested_types.end(); ++it) { | 117 it != requested_types.end(); ++it) { |
| 101 const_iterator data_it = data_.find(*it); | 118 const_iterator data_it = data_.find(*it); |
| 102 if (data_it != data_.end()) { | 119 if (data_it != data_.end()) { |
| 103 ui::SelectionData* data = new SelectionData; | 120 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 } | 121 } |
| 108 } | 122 } |
| 109 | 123 |
| 110 return NULL; | 124 return SelectionData(); |
| 111 } | 125 } |
| 112 | 126 |
| 113 std::vector< ::Atom> SelectionFormatMap::GetTypes() const { | 127 std::vector< ::Atom> SelectionFormatMap::GetTypes() const { |
| 114 std::vector< ::Atom> atoms; | 128 std::vector< ::Atom> atoms; |
| 115 for (const_iterator it = data_.begin(); it != data_.end(); ++it) | 129 for (const_iterator it = data_.begin(); it != data_.end(); ++it) |
| 116 atoms.push_back(it->first); | 130 atoms.push_back(it->first); |
| 117 | 131 |
| 118 return atoms; | 132 return atoms; |
| 119 } | 133 } |
| 120 | 134 |
| 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 /////////////////////////////////////////////////////////////////////////////// | 135 /////////////////////////////////////////////////////////////////////////////// |
| 134 | 136 |
| 135 SelectionData::SelectionData() | 137 SelectionData::SelectionData() |
| 136 : type_(None), | 138 : type_(None), |
| 137 data_(NULL), | |
| 138 size_(0), | |
| 139 owned_(false), | |
| 140 atom_cache_(ui::GetXDisplay(), kSelectionDataAtoms) { | 139 atom_cache_(ui::GetXDisplay(), kSelectionDataAtoms) { |
| 141 } | 140 } |
| 142 | 141 |
| 143 SelectionData::~SelectionData() { | 142 SelectionData::SelectionData( |
| 144 if (owned_) | 143 ::Atom type, |
| 145 XFree(data_); | 144 const scoped_refptr<base::RefCountedMemory>& memory) |
| 145 : type_(type), | |
| 146 memory_(memory), | |
| 147 atom_cache_(ui::GetXDisplay(), kSelectionDataAtoms) { | |
| 146 } | 148 } |
| 147 | 149 |
| 148 void SelectionData::Set(::Atom type, char* data, size_t size, bool owned) { | 150 SelectionData::SelectionData(const SelectionData& rhs) |
| 149 if (owned_) | 151 : type_(rhs.type_), |
| 150 XFree(data_); | 152 memory_(rhs.memory_), |
| 153 atom_cache_(ui::GetXDisplay(), kSelectionDataAtoms) { | |
| 154 } | |
| 151 | 155 |
| 152 type_ = type; | 156 SelectionData::~SelectionData() {} |
| 153 data_ = data; | 157 |
| 154 size_ = size; | 158 SelectionData& SelectionData::operator=(const SelectionData& rhs) { |
| 155 owned_ = owned; | 159 type_ = rhs.type_; |
| 160 memory_ = rhs.memory_; | |
| 161 // TODO(erg): In some future where we have to support multiple X Displays, | |
| 162 // the following will also need to deal with the display. | |
| 163 return *this; | |
| 164 } | |
| 165 | |
| 166 bool SelectionData::IsValid() const { | |
| 167 return type_ != None; | |
| 168 } | |
| 169 | |
| 170 ::Atom SelectionData::GetType() const { | |
| 171 return type_; | |
| 172 } | |
| 173 | |
| 174 const unsigned char* SelectionData::GetData() const { | |
| 175 return memory_ ? memory_->front() : NULL; | |
| 176 } | |
| 177 | |
| 178 size_t SelectionData::GetSize() const { | |
| 179 return memory_ ? memory_->size() : 0; | |
| 156 } | 180 } |
| 157 | 181 |
| 158 std::string SelectionData::GetText() const { | 182 std::string SelectionData::GetText() const { |
| 159 if (type_ == atom_cache_.GetAtom(kUtf8String) || | 183 if (type_ == atom_cache_.GetAtom(kUtf8String) || |
| 160 type_ == atom_cache_.GetAtom(kText)) { | 184 type_ == atom_cache_.GetAtom(kText)) { |
| 161 return std::string(data_, size_); | 185 return RefCountedMemoryToString(memory_); |
| 162 } else if (type_ == atom_cache_.GetAtom(kString)) { | 186 } else if (type_ == atom_cache_.GetAtom(kString)) { |
| 163 std::string result; | 187 std::string result; |
| 164 base::ConvertToUtf8AndNormalize(std::string(data_, size_), | 188 base::ConvertToUtf8AndNormalize(RefCountedMemoryToString(memory_), |
| 165 base::kCodepageLatin1, | 189 base::kCodepageLatin1, |
| 166 &result); | 190 &result); |
| 167 return result; | 191 return result; |
| 168 } else { | 192 } else { |
| 169 // BTW, I looked at COMPOUND_TEXT, and there's no way we're going to | 193 // BTW, I looked at COMPOUND_TEXT, and there's no way we're going to |
| 170 // support that. Yuck. | 194 // support that. Yuck. |
| 171 NOTREACHED(); | 195 NOTREACHED(); |
| 172 return std::string(); | 196 return std::string(); |
| 173 } | 197 } |
| 174 } | 198 } |
| 175 | 199 |
| 176 string16 SelectionData::GetHtml() const { | 200 string16 SelectionData::GetHtml() const { |
| 177 string16 markup; | 201 string16 markup; |
| 178 | 202 |
| 179 if (type_ == atom_cache_.GetAtom(Clipboard::kMimeTypeHTML)) { | 203 if (type_ == atom_cache_.GetAtom(Clipboard::kMimeTypeHTML)) { |
| 204 const unsigned char* data = GetData(); | |
| 205 size_t size = GetSize(); | |
| 206 | |
| 180 // If the data starts with 0xFEFF, i.e., Byte Order Mark, assume it is | 207 // If the data starts with 0xFEFF, i.e., Byte Order Mark, assume it is |
| 181 // UTF-16, otherwise assume UTF-8. | 208 // UTF-16, otherwise assume UTF-8. |
| 182 if (size_ >= 2 && | 209 if (size >= 2 && |
| 183 reinterpret_cast<const uint16_t*>(data_)[0] == 0xFEFF) { | 210 reinterpret_cast<const uint16_t*>(data)[0] == 0xFEFF) { |
| 184 markup.assign(reinterpret_cast<const uint16_t*>(data_) + 1, | 211 markup.assign(reinterpret_cast<const uint16_t*>(data) + 1, |
| 185 (size_ / 2) - 1); | 212 (size / 2) - 1); |
| 186 } else { | 213 } else { |
| 187 UTF8ToUTF16(reinterpret_cast<const char*>(data_), size_, &markup); | 214 UTF8ToUTF16(reinterpret_cast<const char*>(data), size, &markup); |
| 188 } | 215 } |
| 189 | 216 |
| 190 // If there is a terminating NULL, drop it. | 217 // If there is a terminating NULL, drop it. |
| 191 if (!markup.empty() && markup.at(markup.length() - 1) == '\0') | 218 if (!markup.empty() && markup.at(markup.length() - 1) == '\0') |
| 192 markup.resize(markup.length() - 1); | 219 markup.resize(markup.length() - 1); |
| 193 | 220 |
| 194 return markup; | 221 return markup; |
| 195 } else { | 222 } else { |
| 196 NOTREACHED(); | 223 NOTREACHED(); |
| 197 return markup; | 224 return markup; |
| 198 } | 225 } |
| 199 } | 226 } |
| 200 | 227 |
| 201 void SelectionData::AssignTo(std::string* result) const { | 228 void SelectionData::AssignTo(std::string* result) const { |
| 202 result->assign(data_, size_); | 229 *result = RefCountedMemoryToString(memory_); |
| 203 } | 230 } |
| 204 | 231 |
| 205 void SelectionData::AssignTo(string16* result) const { | 232 void SelectionData::AssignTo(string16* result) const { |
| 206 result->assign(reinterpret_cast<base::char16*>(data_), size_ / 2); | 233 *result = RefCountedMemoryToString16(memory_); |
| 207 } | 234 } |
| 208 | 235 |
| 209 } // namespace ui | 236 } // namespace ui |
| OLD | NEW |