// Copyright (c) 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "ui/base/x/selection_utils.h" #include <set> #include "base/i18n/icu_string_conversions.h" #include "base/logging.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "ui/base/clipboard/clipboard.h" #include "ui/base/x/x11_util.h" #include "ui/gfx/x/x11_atom_cache.h" namespace ui { const char kMimeTypeMozillaURL[] = "text/x-moz-url"; const char kString[] = "STRING"; const char kText[] = "TEXT"; const char kTextPlain[] = "text/plain"; const char kTextPlainUtf8[] = "text/plain;charset=utf-8"; const char kUtf8String[] = "UTF8_STRING"; const char* kSelectionDataAtoms[] = { Clipboard::kMimeTypeHTML, kString, kText, kTextPlain, kTextPlainUtf8, kUtf8String, NULL }; std::vector< ::Atom> GetTextAtomsFrom(const X11AtomCache* atom_cache) { std::vector< ::Atom> atoms; atoms.push_back(atom_cache->GetAtom(kUtf8String)); atoms.push_back(atom_cache->GetAtom(kString)); atoms.push_back(atom_cache->GetAtom(kText)); atoms.push_back(atom_cache->GetAtom(kTextPlain)); atoms.push_back(atom_cache->GetAtom(kTextPlainUtf8)); return atoms; } std::vector< ::Atom> GetURLAtomsFrom(const X11AtomCache* atom_cache) { std::vector< ::Atom> atoms; atoms.push_back(atom_cache->GetAtom(Clipboard::kMimeTypeURIList)); atoms.push_back(atom_cache->GetAtom(kMimeTypeMozillaURL)); return atoms; } std::vector< ::Atom> GetURIListAtomsFrom(const X11AtomCache* atom_cache) { std::vector< ::Atom> atoms; atoms.push_back(atom_cache->GetAtom(Clipboard::kMimeTypeURIList)); return atoms; } void GetAtomIntersection(const std::vector< ::Atom>& desired, const std::vector< ::Atom>& offered, std::vector< ::Atom>* output) { for (std::vector< ::Atom>::const_iterator it = desired.begin(); it != desired.end(); ++it) { std::vector< ::Atom>::const_iterator jt = std::find(offered.begin(), offered.end(), *it); if (jt != offered.end()) output->push_back(*it); } } void AddString16ToVector(const base::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)); } std::vector<std::string> ParseURIList(const SelectionData& data) { // uri-lists are newline separated file lists in URL encoding. std::string unparsed; data.AssignTo(&unparsed); std::vector<std::string> tokens; Tokenize(unparsed, "\n", &tokens); return tokens; } std::string RefCountedMemoryToString( const scoped_refptr<base::RefCountedMemory>& memory) { if (!memory.get()) { NOTREACHED(); return std::string(); } size_t size = memory->size(); if (!size) return std::string(); const unsigned char* front = memory->front(); return std::string(reinterpret_cast<const char*>(front), size); } base::string16 RefCountedMemoryToString16( const scoped_refptr<base::RefCountedMemory>& memory) { if (!memory.get()) { NOTREACHED(); return base::string16(); } size_t size = memory->size(); if (!size) return base::string16(); const unsigned char* front = memory->front(); return base::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_.erase(atom); data_.insert(std::make_pair(atom, item)); } 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()) { return SelectionData(data_it->first, data_it->second); } } return SelectionData(); } std::vector< ::Atom> SelectionFormatMap::GetTypes() const { std::vector< ::Atom> atoms; for (const_iterator it = data_.begin(); it != data_.end(); ++it) atoms.push_back(it->first); return atoms; } /////////////////////////////////////////////////////////////////////////////// SelectionData::SelectionData() : type_(None), atom_cache_(gfx::GetXDisplay(), kSelectionDataAtoms) { } SelectionData::SelectionData( ::Atom type, const scoped_refptr<base::RefCountedMemory>& memory) : type_(type), memory_(memory), atom_cache_(gfx::GetXDisplay(), kSelectionDataAtoms) { } SelectionData::SelectionData(const SelectionData& rhs) : type_(rhs.type_), memory_(rhs.memory_), atom_cache_(gfx::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; } ::Atom SelectionData::GetType() const { return type_; } const unsigned char* SelectionData::GetData() const { return memory_.get() ? memory_->front() : NULL; } size_t SelectionData::GetSize() const { return memory_.get() ? memory_->size() : 0; } std::string SelectionData::GetText() const { if (type_ == atom_cache_.GetAtom(kUtf8String) || type_ == atom_cache_.GetAtom(kText) || type_ == atom_cache_.GetAtom(kTextPlainUtf8)) { return RefCountedMemoryToString(memory_); } else if (type_ == atom_cache_.GetAtom(kString) || type_ == atom_cache_.GetAtom(kTextPlain)) { std::string result; base::ConvertToUtf8AndNormalize(RefCountedMemoryToString(memory_), base::kCodepageLatin1, &result); return result; } else { // BTW, I looked at COMPOUND_TEXT, and there's no way we're going to // support that. Yuck. NOTREACHED(); return std::string(); } } base::string16 SelectionData::GetHtml() const { base::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); } else { base::UTF8ToUTF16(reinterpret_cast<const char*>(data), size, &markup); } // If there is a terminating NULL, drop it. if (!markup.empty() && markup.at(markup.length() - 1) == '\0') markup.resize(markup.length() - 1); return markup; } else { NOTREACHED(); return markup; } } void SelectionData::AssignTo(std::string* result) const { *result = RefCountedMemoryToString(memory_); } void SelectionData::AssignTo(base::string16* result) const { *result = RefCountedMemoryToString16(memory_); } } // namespace ui