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