selection_utils.cc revision 868fa2fe829687343ffae624259930155e16dbd8
1c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// found in the LICENSE file.
4c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
5c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/base/x/selection_utils.h"
6c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
7c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include <set>
8c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
9c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/i18n/icu_string_conversions.h"
10c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/logging.h"
11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
12c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/base/clipboard/clipboard.h"
13c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/base/x/x11_atom_cache.h"
14c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
15c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace ui {
16c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
17c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const char kMimeTypeMozillaURL[] = "text/x-moz-url";
18c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const char kString[] = "STRING";
19c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const char kText[] = "TEXT";
20c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const char kUtf8String[] = "UTF8_STRING";
21c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
22c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const char* kSelectionDataAtoms[] = {
23c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  Clipboard::kMimeTypeHTML,
24c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  kString,
25c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  kText,
26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  kUtf8String,
27c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  NULL
28c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)};
29c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
30c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)std::vector< ::Atom> GetTextAtomsFrom(const X11AtomCache* atom_cache) {
31c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::vector< ::Atom> atoms;
32c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  atoms.push_back(atom_cache->GetAtom(kString));
33c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  atoms.push_back(atom_cache->GetAtom(kText));
34c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  atoms.push_back(atom_cache->GetAtom(kUtf8String));
35c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return atoms;
36c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
37c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
38c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)std::vector< ::Atom> GetURLAtomsFrom(const X11AtomCache* atom_cache) {
39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::vector< ::Atom> atoms;
40c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  atoms.push_back(atom_cache->GetAtom(Clipboard::kMimeTypeURIList));
41c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  atoms.push_back(atom_cache->GetAtom(kMimeTypeMozillaURL));
42c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return atoms;
43c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
44c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
45c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void GetAtomIntersection(const std::vector< ::Atom>& one,
46c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                         const std::vector< ::Atom>& two,
47c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                         std::vector< ::Atom>* output) {
48c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for (std::vector< ::Atom>::const_iterator it = one.begin(); it != one.end();
49c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)       ++it) {
50c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    for (std::vector< ::Atom>::const_iterator jt = two.begin(); jt != two.end();
51c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)         ++jt) {
52c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      if (*it == *jt) {
53c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        output->push_back(*it);
54c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        break;
55c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      }
56c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
57c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
58c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
59c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
60c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)///////////////////////////////////////////////////////////////////////////////
61c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
62c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)SelectionFormatMap::SelectionFormatMap() {}
63c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
64c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)SelectionFormatMap::~SelectionFormatMap() {
65c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // WriteText() inserts the same pointer multiple times for different
66c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // representations; we need to dedupe it.
67c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::set<char*> to_delete;
68c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for (InternalMap::iterator it = data_.begin(); it != data_.end(); ++it)
69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    to_delete.insert(it->second.first);
70c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
71c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for (std::set<char*>::iterator it = to_delete.begin(); it != to_delete.end();
72c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)       ++it) {
73c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    delete [] *it;
74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
75c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
76c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
77c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void SelectionFormatMap::Insert(::Atom atom, char* data, size_t size) {
78c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(data_.find(atom) == data_.end());
79c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  data_.insert(std::make_pair(atom, std::make_pair(data, size)));
80c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
81c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
82c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)///////////////////////////////////////////////////////////////////////////////
83c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)SelectionData::SelectionData(Display* x_display)
85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    : type_(None),
86c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      data_(NULL),
87c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      size_(0),
88c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      owned_(false),
89c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      atom_cache_(x_display, kSelectionDataAtoms) {
90c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
91c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
92c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)SelectionData::~SelectionData() {
93c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (owned_)
94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    XFree(data_);
95c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
96c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
97c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void SelectionData::Set(::Atom type, char* data, size_t size, bool owned) {
98c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (owned_)
99c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    XFree(data_);
100c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
101c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  type_ = type;
102c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  data_ = data;
103c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  size_ = size;
104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  owned_ = owned;
105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
106c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
107c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)std::string SelectionData::GetText() const {
108c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (type_ == atom_cache_.GetAtom(kUtf8String) ||
109c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      type_ == atom_cache_.GetAtom(kText)) {
110c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return std::string(data_, size_);
111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  } else if (type_ == atom_cache_.GetAtom(kString)) {
112c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    std::string result;
113c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    base::ConvertToUtf8AndNormalize(std::string(data_, size_),
114c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                    base::kCodepageLatin1,
115c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                    &result);
116c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return result;
117c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  } else {
118c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // BTW, I looked at COMPOUND_TEXT, and there's no way we're going to
119c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // support that. Yuck.
120c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    NOTREACHED();
121c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return std::string();
122c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
123c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
124c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
125c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)string16 SelectionData::GetHtml() const {
126c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  string16 markup;
127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (type_ == atom_cache_.GetAtom(Clipboard::kMimeTypeHTML)) {
129c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // If the data starts with 0xFEFF, i.e., Byte Order Mark, assume it is
130c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // UTF-16, otherwise assume UTF-8.
131c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (size_ >= 2 &&
132c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        reinterpret_cast<const uint16_t*>(data_)[0] == 0xFEFF) {
133c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      markup.assign(reinterpret_cast<const uint16_t*>(data_) + 1,
134c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                    (size_ / 2) - 1);
135c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    } else {
136c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      UTF8ToUTF16(reinterpret_cast<const char*>(data_), size_, &markup);
137c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
138c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
139c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // If there is a terminating NULL, drop it.
140c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!markup.empty() && markup.at(markup.length() - 1) == '\0')
141c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      markup.resize(markup.length() - 1);
142c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
143c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return markup;
144c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  } else {
145c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    NOTREACHED();
146c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return markup;
147c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
148c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
149c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
150c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void SelectionData::AssignTo(std::string* result) const {
151c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  result->assign(data_, size_);
152c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
153c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
154c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void SelectionData::AssignTo(string16* result) const {
155c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  result->assign(reinterpret_cast<base::char16*>(data_), size_ / 2);
156c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
157c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
158c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}  // namespace ui
159