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/string_util.h"
     12 #include "base/strings/utf_string_conversions.h"
     13 #include "ui/base/clipboard/clipboard.h"
     14 #include "ui/base/x/x11_util.h"
     15 #include "ui/gfx/x/x11_atom_cache.h"
     16 
     17 namespace ui {
     18 
     19 const char kMimeTypeMozillaURL[] = "text/x-moz-url";
     20 const char kString[] = "STRING";
     21 const char kText[] = "TEXT";
     22 const char kTextPlain[] = "text/plain";
     23 const char kTextPlainUtf8[] = "text/plain;charset=utf-8";
     24 const char kUtf8String[] = "UTF8_STRING";
     25 
     26 const char* kSelectionDataAtoms[] = {
     27   Clipboard::kMimeTypeHTML,
     28   kString,
     29   kText,
     30   kTextPlain,
     31   kTextPlainUtf8,
     32   kUtf8String,
     33   NULL
     34 };
     35 
     36 std::vector< ::Atom> GetTextAtomsFrom(const X11AtomCache* atom_cache) {
     37   std::vector< ::Atom> atoms;
     38   atoms.push_back(atom_cache->GetAtom(kUtf8String));
     39   atoms.push_back(atom_cache->GetAtom(kString));
     40   atoms.push_back(atom_cache->GetAtom(kText));
     41   atoms.push_back(atom_cache->GetAtom(kTextPlain));
     42   atoms.push_back(atom_cache->GetAtom(kTextPlainUtf8));
     43   return atoms;
     44 }
     45 
     46 std::vector< ::Atom> GetURLAtomsFrom(const X11AtomCache* atom_cache) {
     47   std::vector< ::Atom> atoms;
     48   atoms.push_back(atom_cache->GetAtom(Clipboard::kMimeTypeURIList));
     49   atoms.push_back(atom_cache->GetAtom(kMimeTypeMozillaURL));
     50   return atoms;
     51 }
     52 
     53 std::vector< ::Atom> GetURIListAtomsFrom(const X11AtomCache* atom_cache) {
     54   std::vector< ::Atom> atoms;
     55   atoms.push_back(atom_cache->GetAtom(Clipboard::kMimeTypeURIList));
     56   return atoms;
     57 }
     58 
     59 void GetAtomIntersection(const std::vector< ::Atom>& desired,
     60                          const std::vector< ::Atom>& offered,
     61                          std::vector< ::Atom>* output) {
     62   for (std::vector< ::Atom>::const_iterator it = desired.begin();
     63        it != desired.end(); ++it) {
     64     std::vector< ::Atom>::const_iterator jt =
     65       std::find(offered.begin(), offered.end(), *it);
     66     if (jt != offered.end())
     67       output->push_back(*it);
     68   }
     69 }
     70 
     71 void AddString16ToVector(const base::string16& str,
     72                          std::vector<unsigned char>* bytes) {
     73   const unsigned char* front =
     74       reinterpret_cast<const unsigned char*>(str.data());
     75   bytes->insert(bytes->end(), front, front + (str.size() * 2));
     76 }
     77 
     78 std::vector<std::string> ParseURIList(const SelectionData& data) {
     79   // uri-lists are newline separated file lists in URL encoding.
     80   std::string unparsed;
     81   data.AssignTo(&unparsed);
     82 
     83   std::vector<std::string> tokens;
     84   Tokenize(unparsed, "\n", &tokens);
     85   return tokens;
     86 }
     87 
     88 std::string RefCountedMemoryToString(
     89     const scoped_refptr<base::RefCountedMemory>& memory) {
     90   if (!memory.get()) {
     91     NOTREACHED();
     92     return std::string();
     93   }
     94 
     95   size_t size = memory->size();
     96   if (!size)
     97     return std::string();
     98 
     99   const unsigned char* front = memory->front();
    100   return std::string(reinterpret_cast<const char*>(front), size);
    101 }
    102 
    103 base::string16 RefCountedMemoryToString16(
    104     const scoped_refptr<base::RefCountedMemory>& memory) {
    105   if (!memory.get()) {
    106     NOTREACHED();
    107     return base::string16();
    108   }
    109 
    110   size_t size = memory->size();
    111   if (!size)
    112     return base::string16();
    113 
    114   const unsigned char* front = memory->front();
    115   return base::string16(reinterpret_cast<const base::char16*>(front), size / 2);
    116 }
    117 
    118 ///////////////////////////////////////////////////////////////////////////////
    119 
    120 SelectionFormatMap::SelectionFormatMap() {}
    121 
    122 SelectionFormatMap::~SelectionFormatMap() {}
    123 
    124 void SelectionFormatMap::Insert(
    125     ::Atom atom,
    126     const scoped_refptr<base::RefCountedMemory>& item) {
    127   data_.erase(atom);
    128   data_.insert(std::make_pair(atom, item));
    129 }
    130 
    131 ui::SelectionData SelectionFormatMap::GetFirstOf(
    132     const std::vector< ::Atom>& requested_types) const {
    133   for (std::vector< ::Atom>::const_iterator it = requested_types.begin();
    134        it != requested_types.end(); ++it) {
    135     const_iterator data_it = data_.find(*it);
    136     if (data_it != data_.end()) {
    137       return SelectionData(data_it->first, data_it->second);
    138     }
    139   }
    140 
    141   return SelectionData();
    142 }
    143 
    144 std::vector< ::Atom> SelectionFormatMap::GetTypes() const {
    145   std::vector< ::Atom> atoms;
    146   for (const_iterator it = data_.begin(); it != data_.end(); ++it)
    147     atoms.push_back(it->first);
    148 
    149   return atoms;
    150 }
    151 
    152 ///////////////////////////////////////////////////////////////////////////////
    153 
    154 SelectionData::SelectionData()
    155     : type_(None),
    156       atom_cache_(gfx::GetXDisplay(), kSelectionDataAtoms) {
    157 }
    158 
    159 SelectionData::SelectionData(
    160     ::Atom type,
    161     const scoped_refptr<base::RefCountedMemory>& memory)
    162     : type_(type),
    163       memory_(memory),
    164       atom_cache_(gfx::GetXDisplay(), kSelectionDataAtoms) {
    165 }
    166 
    167 SelectionData::SelectionData(const SelectionData& rhs)
    168     : type_(rhs.type_),
    169       memory_(rhs.memory_),
    170       atom_cache_(gfx::GetXDisplay(), kSelectionDataAtoms) {
    171 }
    172 
    173 SelectionData::~SelectionData() {}
    174 
    175 SelectionData& SelectionData::operator=(const SelectionData& rhs) {
    176   type_ = rhs.type_;
    177   memory_ = rhs.memory_;
    178   // TODO(erg): In some future where we have to support multiple X Displays,
    179   // the following will also need to deal with the display.
    180   return *this;
    181 }
    182 
    183 bool SelectionData::IsValid() const {
    184   return type_ != None;
    185 }
    186 
    187 ::Atom SelectionData::GetType() const {
    188   return type_;
    189 }
    190 
    191 const unsigned char* SelectionData::GetData() const {
    192   return memory_.get() ? memory_->front() : NULL;
    193 }
    194 
    195 size_t SelectionData::GetSize() const {
    196   return memory_.get() ? memory_->size() : 0;
    197 }
    198 
    199 std::string SelectionData::GetText() const {
    200   if (type_ == atom_cache_.GetAtom(kUtf8String) ||
    201       type_ == atom_cache_.GetAtom(kText) ||
    202       type_ == atom_cache_.GetAtom(kTextPlainUtf8)) {
    203     return RefCountedMemoryToString(memory_);
    204   } else if (type_ == atom_cache_.GetAtom(kString) ||
    205              type_ == atom_cache_.GetAtom(kTextPlain)) {
    206     std::string result;
    207     base::ConvertToUtf8AndNormalize(RefCountedMemoryToString(memory_),
    208                                     base::kCodepageLatin1,
    209                                     &result);
    210     return result;
    211   } else {
    212     // BTW, I looked at COMPOUND_TEXT, and there's no way we're going to
    213     // support that. Yuck.
    214     NOTREACHED();
    215     return std::string();
    216   }
    217 }
    218 
    219 base::string16 SelectionData::GetHtml() const {
    220   base::string16 markup;
    221 
    222   if (type_ == atom_cache_.GetAtom(Clipboard::kMimeTypeHTML)) {
    223     const unsigned char* data = GetData();
    224     size_t size = GetSize();
    225 
    226     // If the data starts with 0xFEFF, i.e., Byte Order Mark, assume it is
    227     // UTF-16, otherwise assume UTF-8.
    228     if (size >= 2 &&
    229         reinterpret_cast<const uint16_t*>(data)[0] == 0xFEFF) {
    230       markup.assign(reinterpret_cast<const uint16_t*>(data) + 1,
    231                     (size / 2) - 1);
    232     } else {
    233       base::UTF8ToUTF16(reinterpret_cast<const char*>(data), size, &markup);
    234     }
    235 
    236     // If there is a terminating NULL, drop it.
    237     if (!markup.empty() && markup.at(markup.length() - 1) == '\0')
    238       markup.resize(markup.length() - 1);
    239 
    240     return markup;
    241   } else {
    242     NOTREACHED();
    243     return markup;
    244   }
    245 }
    246 
    247 void SelectionData::AssignTo(std::string* result) const {
    248   *result = RefCountedMemoryToString(memory_);
    249 }
    250 
    251 void SelectionData::AssignTo(base::string16* result) const {
    252   *result = RefCountedMemoryToString16(memory_);
    253 }
    254 
    255 }  // namespace ui
    256