Home | History | Annotate | Download | only in x
      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_atom_cache.h"
     14 #include "ui/base/x/x11_util.h"
     15 
     16 namespace ui {
     17 
     18 const char kMimeTypeMozillaURL[] = "text/x-moz-url";
     19 const char kString[] = "STRING";
     20 const char kText[] = "TEXT";
     21 const char kUtf8String[] = "UTF8_STRING";
     22 
     23 const char* kSelectionDataAtoms[] = {
     24   Clipboard::kMimeTypeHTML,
     25   kString,
     26   kText,
     27   kUtf8String,
     28   NULL
     29 };
     30 
     31 std::vector< ::Atom> GetTextAtomsFrom(const X11AtomCache* atom_cache) {
     32   std::vector< ::Atom> atoms;
     33   atoms.push_back(atom_cache->GetAtom(kString));
     34   atoms.push_back(atom_cache->GetAtom(kText));
     35   atoms.push_back(atom_cache->GetAtom(kUtf8String));
     36   return atoms;
     37 }
     38 
     39 std::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 
     46 void GetAtomIntersection(const std::vector< ::Atom>& one,
     47                          const std::vector< ::Atom>& two,
     48                          std::vector< ::Atom>* output) {
     49   for (std::vector< ::Atom>::const_iterator it = one.begin(); it != one.end();
     50        ++it) {
     51     for (std::vector< ::Atom>::const_iterator jt = two.begin(); jt != two.end();
     52          ++jt) {
     53       if (*it == *jt) {
     54         output->push_back(*it);
     55         break;
     56       }
     57     }
     58   }
     59 }
     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.get()) {
     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.get()) {
     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 
     98 ///////////////////////////////////////////////////////////////////////////////
     99 
    100 SelectionFormatMap::SelectionFormatMap() {}
    101 
    102 SelectionFormatMap::~SelectionFormatMap() {}
    103 
    104 void SelectionFormatMap::Insert(
    105     ::Atom atom,
    106     const scoped_refptr<base::RefCountedMemory>& item) {
    107   data_.insert(std::make_pair(atom, item));
    108 }
    109 
    110 ui::SelectionData SelectionFormatMap::GetFirstOf(
    111     const std::vector< ::Atom>& requested_types) const {
    112   for (std::vector< ::Atom>::const_iterator it = requested_types.begin();
    113        it != requested_types.end(); ++it) {
    114     const_iterator data_it = data_.find(*it);
    115     if (data_it != data_.end()) {
    116       return SelectionData(data_it->first, data_it->second);
    117     }
    118   }
    119 
    120   return SelectionData();
    121 }
    122 
    123 std::vector< ::Atom> SelectionFormatMap::GetTypes() const {
    124   std::vector< ::Atom> atoms;
    125   for (const_iterator it = data_.begin(); it != data_.end(); ++it)
    126     atoms.push_back(it->first);
    127 
    128   return atoms;
    129 }
    130 
    131 ///////////////////////////////////////////////////////////////////////////////
    132 
    133 SelectionData::SelectionData()
    134     : type_(None),
    135       atom_cache_(ui::GetXDisplay(), kSelectionDataAtoms) {
    136 }
    137 
    138 SelectionData::SelectionData(
    139     ::Atom type,
    140     const scoped_refptr<base::RefCountedMemory>& memory)
    141     : type_(type),
    142       memory_(memory),
    143       atom_cache_(ui::GetXDisplay(), kSelectionDataAtoms) {
    144 }
    145 
    146 SelectionData::SelectionData(const SelectionData& rhs)
    147     : type_(rhs.type_),
    148       memory_(rhs.memory_),
    149       atom_cache_(ui::GetXDisplay(), kSelectionDataAtoms) {
    150 }
    151 
    152 SelectionData::~SelectionData() {}
    153 
    154 SelectionData& SelectionData::operator=(const SelectionData& rhs) {
    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_.get() ? memory_->front() : NULL;
    172 }
    173 
    174 size_t SelectionData::GetSize() const {
    175   return memory_.get() ? memory_->size() : 0;
    176 }
    177 
    178 std::string SelectionData::GetText() const {
    179   if (type_ == atom_cache_.GetAtom(kUtf8String) ||
    180       type_ == atom_cache_.GetAtom(kText)) {
    181     return RefCountedMemoryToString(memory_);
    182   } else if (type_ == atom_cache_.GetAtom(kString)) {
    183     std::string result;
    184     base::ConvertToUtf8AndNormalize(RefCountedMemoryToString(memory_),
    185                                     base::kCodepageLatin1,
    186                                     &result);
    187     return result;
    188   } else {
    189     // BTW, I looked at COMPOUND_TEXT, and there's no way we're going to
    190     // support that. Yuck.
    191     NOTREACHED();
    192     return std::string();
    193   }
    194 }
    195 
    196 string16 SelectionData::GetHtml() const {
    197   string16 markup;
    198 
    199   if (type_ == atom_cache_.GetAtom(Clipboard::kMimeTypeHTML)) {
    200     const unsigned char* data = GetData();
    201     size_t size = GetSize();
    202 
    203     // If the data starts with 0xFEFF, i.e., Byte Order Mark, assume it is
    204     // UTF-16, otherwise assume UTF-8.
    205     if (size >= 2 &&
    206         reinterpret_cast<const uint16_t*>(data)[0] == 0xFEFF) {
    207       markup.assign(reinterpret_cast<const uint16_t*>(data) + 1,
    208                     (size / 2) - 1);
    209     } else {
    210       UTF8ToUTF16(reinterpret_cast<const char*>(data), size, &markup);
    211     }
    212 
    213     // If there is a terminating NULL, drop it.
    214     if (!markup.empty() && markup.at(markup.length() - 1) == '\0')
    215       markup.resize(markup.length() - 1);
    216 
    217     return markup;
    218   } else {
    219     NOTREACHED();
    220     return markup;
    221   }
    222 }
    223 
    224 void SelectionData::AssignTo(std::string* result) const {
    225   *result = RefCountedMemoryToString(memory_);
    226 }
    227 
    228 void SelectionData::AssignTo(string16* result) const {
    229   *result = RefCountedMemoryToString16(memory_);
    230 }
    231 
    232 }  // namespace ui
    233