Chromium Code Reviews| Index: ui/base/x/selection_utils.cc |
| diff --git a/ui/base/x/selection_utils.cc b/ui/base/x/selection_utils.cc |
| index 5dd6f681ce129ab01388a4068fcd5154410dffc5..f89bc6ced6a6624a433c64d64a08e36606742d67 100644 |
| --- a/ui/base/x/selection_utils.cc |
| +++ b/ui/base/x/selection_utils.cc |
| @@ -58,56 +58,70 @@ void GetAtomIntersection(const std::vector< ::Atom>& one, |
| } |
| } |
| -/////////////////////////////////////////////////////////////////////////////// |
| - |
| -SelectionFormatMap::SelectionFormatMap() {} |
| +void AddString16ToVector(const string16& str, |
| + std::vector<unsigned char>* bytes) { |
| + const unsigned char* front = |
| + reinterpret_cast<const unsigned char*>(str.data()); |
| + bytes->insert(bytes->end(), front, front + (str.size() * 2)); |
| +} |
| -SelectionFormatMap::~SelectionFormatMap() { |
| - // WriteText() inserts the same pointer multiple times for different |
| - // representations; we need to dedupe it. |
| - std::set<char*> to_delete; |
| - for (InternalMap::iterator it = data_.begin(); it != data_.end(); ++it) |
| - to_delete.insert(it->second.first); |
| +std::string RefCountedMemoryToString( |
| + const scoped_refptr<base::RefCountedMemory>& memory) { |
| + if (!memory) { |
| + NOTREACHED(); |
| + return std::string(); |
| + } |
| - for (std::set<char*>::iterator it = to_delete.begin(); it != to_delete.end(); |
| - ++it) { |
| - delete [] *it; |
| + size_t size = memory->size(); |
| + if (!size) { |
| + 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
|
| + return std::string(); |
| } |
| + |
| + const unsigned char* front = memory->front(); |
| + return std::string(reinterpret_cast<const char*>(front), size); |
| } |
| -void SelectionFormatMap::Insert(::Atom atom, char* data, size_t size) { |
| - // Views code often inserts the same content multiple times, so we have to |
| - // free old data. Only call delete when it's the last pointer we have to that |
| - // data. |
| - InternalMap::iterator exists_it = data_.find(atom); |
| - if (exists_it != data_.end()) { |
| - int count = 0; |
| - for (InternalMap::iterator it = data_.begin(); it != data_.end(); ++it) { |
| - if (it->second.first == exists_it->second.first) |
| - count++; |
| - } |
| +string16 RefCountedMemoryToString16( |
| + const scoped_refptr<base::RefCountedMemory>& memory) { |
| + if (!memory) { |
| + NOTREACHED(); |
| + return string16(); |
| + } |
| - if (count == 1) |
| - delete [] exists_it->second.first; |
| + size_t size = memory->size(); |
| + if (!size) { |
| + NOTREACHED(); |
| + return string16(); |
| } |
| - data_.insert(std::make_pair(atom, std::make_pair(data, size))); |
| + const unsigned char* front = memory->front(); |
| + return string16(reinterpret_cast<const base::char16*>(front), size / 2); |
| +} |
| + |
| +/////////////////////////////////////////////////////////////////////////////// |
| + |
| +SelectionFormatMap::SelectionFormatMap() {} |
| + |
| +SelectionFormatMap::~SelectionFormatMap() {} |
| + |
| +void SelectionFormatMap::Insert( |
| + ::Atom atom, |
| + const scoped_refptr<base::RefCountedMemory>& item) { |
| + data_.insert(std::make_pair(atom, item)); |
| } |
| -ui::SelectionData* SelectionFormatMap::GetFirstOf( |
| +ui::SelectionData SelectionFormatMap::GetFirstOf( |
| const std::vector< ::Atom>& requested_types) const { |
| for (std::vector< ::Atom>::const_iterator it = requested_types.begin(); |
| it != requested_types.end(); ++it) { |
| const_iterator data_it = data_.find(*it); |
| if (data_it != data_.end()) { |
| - ui::SelectionData* data = new SelectionData; |
| - data->Set(data_it->first, data_it->second.first, data_it->second.second, |
| - false); |
| - return data; |
| + return SelectionData(data_it->first, data_it->second); |
| } |
| } |
| - return NULL; |
| + return SelectionData(); |
| } |
| std::vector< ::Atom> SelectionFormatMap::GetTypes() const { |
| @@ -118,50 +132,60 @@ std::vector< ::Atom> SelectionFormatMap::GetTypes() const { |
| return atoms; |
| } |
| -scoped_ptr<SelectionFormatMap> SelectionFormatMap::Clone() const { |
| - scoped_ptr<SelectionFormatMap> ret(new SelectionFormatMap); |
| - |
| - for (const_iterator it = data_.begin(); it != data_.end(); ++it) { |
| - char* data_copy = new char[it->second.second]; |
| - memcpy(data_copy, it->second.first, it->second.second); |
| - ret->Insert(it->first, data_copy, it->second.second); |
| - } |
| - |
| - return ret.Pass(); |
| -} |
| - |
| /////////////////////////////////////////////////////////////////////////////// |
| SelectionData::SelectionData() |
| : type_(None), |
| - data_(NULL), |
| - size_(0), |
| - owned_(false), |
| atom_cache_(ui::GetXDisplay(), kSelectionDataAtoms) { |
| } |
| -SelectionData::~SelectionData() { |
| - if (owned_) |
| - XFree(data_); |
| +SelectionData::SelectionData( |
| + ::Atom type, |
| + const scoped_refptr<base::RefCountedMemory>& memory) |
| + : type_(type), |
| + memory_(memory), |
| + atom_cache_(ui::GetXDisplay(), kSelectionDataAtoms) { |
| +} |
| + |
| +SelectionData::SelectionData(const SelectionData& rhs) |
| + : type_(rhs.type_), |
| + memory_(rhs.memory_), |
| + atom_cache_(ui::GetXDisplay(), kSelectionDataAtoms) { |
| +} |
| + |
| +SelectionData::~SelectionData() {} |
| + |
| +SelectionData& SelectionData::operator=(const SelectionData& rhs) { |
| + type_ = rhs.type_; |
| + memory_ = rhs.memory_; |
| + // TODO(erg): In some future where we have to support multiple X Displays, |
| + // the following will also need to deal with the display. |
| + return *this; |
| +} |
| + |
| +bool SelectionData::IsValid() const { |
| + return type_ != None; |
| } |
| -void SelectionData::Set(::Atom type, char* data, size_t size, bool owned) { |
| - if (owned_) |
| - XFree(data_); |
| +::Atom SelectionData::GetType() const { |
| + return type_; |
| +} |
| - type_ = type; |
| - data_ = data; |
| - size_ = size; |
| - owned_ = owned; |
| +const unsigned char* SelectionData::GetData() const { |
| + return memory_ ? memory_->front() : NULL; |
| +} |
| + |
| +size_t SelectionData::GetSize() const { |
| + return memory_ ? memory_->size() : 0; |
| } |
| std::string SelectionData::GetText() const { |
| if (type_ == atom_cache_.GetAtom(kUtf8String) || |
| type_ == atom_cache_.GetAtom(kText)) { |
| - return std::string(data_, size_); |
| + return RefCountedMemoryToString(memory_); |
| } else if (type_ == atom_cache_.GetAtom(kString)) { |
| std::string result; |
| - base::ConvertToUtf8AndNormalize(std::string(data_, size_), |
| + base::ConvertToUtf8AndNormalize(RefCountedMemoryToString(memory_), |
| base::kCodepageLatin1, |
| &result); |
| return result; |
| @@ -177,14 +201,17 @@ string16 SelectionData::GetHtml() const { |
| string16 markup; |
| if (type_ == atom_cache_.GetAtom(Clipboard::kMimeTypeHTML)) { |
| + const unsigned char* data = GetData(); |
| + size_t size = GetSize(); |
| + |
| // If the data starts with 0xFEFF, i.e., Byte Order Mark, assume it is |
| // UTF-16, otherwise assume UTF-8. |
| - if (size_ >= 2 && |
| - reinterpret_cast<const uint16_t*>(data_)[0] == 0xFEFF) { |
| - markup.assign(reinterpret_cast<const uint16_t*>(data_) + 1, |
| - (size_ / 2) - 1); |
| + if (size >= 2 && |
| + reinterpret_cast<const uint16_t*>(data)[0] == 0xFEFF) { |
| + markup.assign(reinterpret_cast<const uint16_t*>(data) + 1, |
| + (size / 2) - 1); |
| } else { |
| - UTF8ToUTF16(reinterpret_cast<const char*>(data_), size_, &markup); |
| + UTF8ToUTF16(reinterpret_cast<const char*>(data), size, &markup); |
| } |
| // If there is a terminating NULL, drop it. |
| @@ -199,11 +226,11 @@ string16 SelectionData::GetHtml() const { |
| } |
| void SelectionData::AssignTo(std::string* result) const { |
| - result->assign(data_, size_); |
| + *result = RefCountedMemoryToString(memory_); |
| } |
| void SelectionData::AssignTo(string16* result) const { |
| - result->assign(reinterpret_cast<base::char16*>(data_), size_ / 2); |
| + *result = RefCountedMemoryToString16(memory_); |
| } |
| } // namespace ui |