OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ui/base/clipboard/clipboard.h" | 5 #include "ui/base/clipboard/clipboard.h" |
6 | 6 |
7 #include <X11/extensions/Xfixes.h> | 7 #include <X11/extensions/Xfixes.h> |
8 #include <X11/Xatom.h> | 8 #include <X11/Xatom.h> |
9 #include <list> | 9 #include <list> |
10 #include <set> | 10 #include <set> |
11 | 11 |
12 #include "base/basictypes.h" | 12 #include "base/basictypes.h" |
13 #include "base/files/file_path.h" | 13 #include "base/files/file_path.h" |
14 #include "base/i18n/icu_string_conversions.h" | |
15 #include "base/logging.h" | 14 #include "base/logging.h" |
16 #include "base/memory/scoped_ptr.h" | 15 #include "base/memory/scoped_ptr.h" |
17 #include "base/memory/singleton.h" | 16 #include "base/memory/singleton.h" |
18 #include "base/message_pump_aurax11.h" | 17 #include "base/message_pump_aurax11.h" |
19 #include "base/message_pump_observer.h" | 18 #include "base/message_pump_observer.h" |
20 #include "base/stl_util.h" | 19 #include "base/stl_util.h" |
21 #include "base/utf_string_conversions.h" | 20 #include "base/utf_string_conversions.h" |
22 #include "third_party/skia/include/core/SkBitmap.h" | 21 #include "third_party/skia/include/core/SkBitmap.h" |
23 #include "ui/base/clipboard/custom_data_helper.h" | 22 #include "ui/base/clipboard/custom_data_helper.h" |
24 #include "ui/base/x/selection_owner.h" | 23 #include "ui/base/x/selection_owner.h" |
25 #include "ui/base/x/selection_requestor.h" | 24 #include "ui/base/x/selection_requestor.h" |
26 #include "ui/base/x/selection_utils.h" | 25 #include "ui/base/x/selection_utils.h" |
27 #include "ui/base/x/x11_atom_cache.h" | 26 #include "ui/base/x/x11_atom_cache.h" |
28 #include "ui/base/x/x11_util.h" | 27 #include "ui/base/x/x11_util.h" |
29 | 28 |
30 #include "ui/gfx/size.h" | 29 #include "ui/gfx/size.h" |
31 | 30 |
32 namespace ui { | 31 namespace ui { |
33 | 32 |
34 namespace { | 33 namespace { |
35 | 34 |
36 const char kClipboard[] = "CLIPBOARD"; | 35 const char kClipboard[] = "CLIPBOARD"; |
37 const char kMimeTypeBitmap[] = "image/bmp"; | 36 const char kMimeTypeBitmap[] = "image/bmp"; |
38 const char kMimeTypeFilename[] = "chromium/filename"; | 37 const char kMimeTypeFilename[] = "chromium/filename"; |
39 const char kMimeTypeMozillaURL[] = "text/x-moz-url"; | |
40 const char kMimeTypePepperCustomData[] = "chromium/x-pepper-custom-data"; | 38 const char kMimeTypePepperCustomData[] = "chromium/x-pepper-custom-data"; |
41 const char kMimeTypeWebkitSmartPaste[] = "chromium/x-webkit-paste"; | 39 const char kMimeTypeWebkitSmartPaste[] = "chromium/x-webkit-paste"; |
42 const char kSourceTagType[] = "org.chromium.source-tag"; | 40 const char kSourceTagType[] = "org.chromium.source-tag"; |
43 const char kString[] = "STRING"; | |
44 const char kTargets[] = "TARGETS"; | 41 const char kTargets[] = "TARGETS"; |
45 const char kText[] = "TEXT"; | |
46 const char kUtf8String[] = "UTF8_STRING"; | |
47 | 42 |
48 const char* kAtomsToCache[] = { | 43 const char* kAtomsToCache[] = { |
49 kClipboard, | 44 kClipboard, |
50 kMimeTypeBitmap, | 45 kMimeTypeBitmap, |
51 kMimeTypeFilename, | 46 kMimeTypeFilename, |
52 kMimeTypeMozillaURL, | 47 kMimeTypeMozillaURL, |
53 kMimeTypeWebkitSmartPaste, | 48 kMimeTypeWebkitSmartPaste, |
54 kSourceTagType, | 49 kSourceTagType, |
55 kString, | 50 kString, |
56 kTargets, | 51 kTargets, |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
143 | 138 |
144 /////////////////////////////////////////////////////////////////////////////// | 139 /////////////////////////////////////////////////////////////////////////////// |
145 | 140 |
146 // Represents a list of possible return types. Copy constructable. | 141 // Represents a list of possible return types. Copy constructable. |
147 class TargetList { | 142 class TargetList { |
148 public: | 143 public: |
149 typedef std::vector< ::Atom> AtomVector; | 144 typedef std::vector< ::Atom> AtomVector; |
150 | 145 |
151 TargetList(const AtomVector& target_list, X11AtomCache* atom_cache); | 146 TargetList(const AtomVector& target_list, X11AtomCache* atom_cache); |
152 | 147 |
| 148 const AtomVector& target_list() { return target_list_; } |
| 149 |
153 bool ContainsText() const; | 150 bool ContainsText() const; |
154 bool ContainsFormat(const Clipboard::FormatType& format_type) const; | 151 bool ContainsFormat(const Clipboard::FormatType& format_type) const; |
155 bool ContainsAtom(::Atom atom) const; | 152 bool ContainsAtom(::Atom atom) const; |
156 | 153 |
157 private: | 154 private: |
158 AtomVector target_list_; | 155 AtomVector target_list_; |
159 X11AtomCache* atom_cache_; | 156 X11AtomCache* atom_cache_; |
160 }; | 157 }; |
161 | 158 |
162 TargetList::TargetList(const AtomVector& target_list, | 159 TargetList::TargetList(const AtomVector& target_list, |
(...skipping 17 matching lines...) Expand all Loading... |
180 const Clipboard::FormatType& format_type) const { | 177 const Clipboard::FormatType& format_type) const { |
181 ::Atom atom = atom_cache_->GetAtom(format_type.ToString().c_str()); | 178 ::Atom atom = atom_cache_->GetAtom(format_type.ToString().c_str()); |
182 return ContainsAtom(atom); | 179 return ContainsAtom(atom); |
183 } | 180 } |
184 | 181 |
185 bool TargetList::ContainsAtom(::Atom atom) const { | 182 bool TargetList::ContainsAtom(::Atom atom) const { |
186 return find(target_list_.begin(), target_list_.end(), atom) | 183 return find(target_list_.begin(), target_list_.end(), atom) |
187 != target_list_.end(); | 184 != target_list_.end(); |
188 } | 185 } |
189 | 186 |
190 /////////////////////////////////////////////////////////////////////////////// | |
191 | |
192 // A holder for data with optional X11 deletion semantics. | |
193 class SelectionData { | |
194 public: | |
195 // |atom_cache| is still owned by caller. | |
196 explicit SelectionData(X11AtomCache* atom_cache); | |
197 ~SelectionData(); | |
198 | |
199 ::Atom type() const { return type_; } | |
200 char* data() const { return data_; } | |
201 size_t size() const { return size_; } | |
202 | |
203 void Set(::Atom type, char* data, size_t size, bool owned); | |
204 | |
205 // If |type_| is a string type, convert the data to UTF8 and return it. | |
206 std::string GetText() const; | |
207 | |
208 // Assigns the raw data to the string. | |
209 void AssignTo(std::string* result) const; | |
210 | |
211 private: | |
212 ::Atom type_; | |
213 char* data_; | |
214 size_t size_; | |
215 bool owned_; | |
216 | |
217 X11AtomCache* atom_cache_; | |
218 }; | |
219 | |
220 SelectionData::SelectionData(X11AtomCache* atom_cache) | |
221 : type_(None), | |
222 data_(NULL), | |
223 size_(0), | |
224 owned_(false), | |
225 atom_cache_(atom_cache) { | |
226 } | |
227 | |
228 SelectionData::~SelectionData() { | |
229 if (owned_) | |
230 XFree(data_); | |
231 } | |
232 | |
233 void SelectionData::Set(::Atom type, char* data, size_t size, bool owned) { | |
234 if (owned_) | |
235 XFree(data_); | |
236 | |
237 type_ = type; | |
238 data_ = data; | |
239 size_ = size; | |
240 owned_ = owned; | |
241 } | |
242 | |
243 std::string SelectionData::GetText() const { | |
244 if (type_ == atom_cache_->GetAtom(kUtf8String) || | |
245 type_ == atom_cache_->GetAtom(kText)) { | |
246 return std::string(data_, size_); | |
247 } else if (type_ == atom_cache_->GetAtom(kString)) { | |
248 std::string result; | |
249 base::ConvertToUtf8AndNormalize(std::string(data_, size_), | |
250 base::kCodepageLatin1, | |
251 &result); | |
252 return result; | |
253 } else { | |
254 // BTW, I looked at COMPOUND_TEXT, and there's no way we're going to | |
255 // support that. Yuck. | |
256 NOTREACHED(); | |
257 return std::string(); | |
258 } | |
259 } | |
260 | |
261 void SelectionData::AssignTo(std::string* result) const { | |
262 result->assign(data_, size_); | |
263 } | |
264 | |
265 } // namespace | 187 } // namespace |
266 | 188 |
267 /////////////////////////////////////////////////////////////////////////////// | 189 /////////////////////////////////////////////////////////////////////////////// |
268 | 190 |
269 // I would love for the FormatType to really be a wrapper around an X11 ::Atom, | 191 // I would love for the FormatType to really be a wrapper around an X11 ::Atom, |
270 // but there are a few problems. Chromeos unit tests spawn a new X11 server for | 192 // but there are a few problems. Chromeos unit tests spawn a new X11 server for |
271 // each test, so Atom numeric values don't persist across tests. We could still | 193 // each test, so Atom numeric values don't persist across tests. We could still |
272 // maybe deal with that if we didn't have static accessor methods everywhere. | 194 // maybe deal with that if we didn't have static accessor methods everywhere. |
273 | 195 |
274 Clipboard::FormatType::FormatType() { | 196 Clipboard::FormatType::FormatType() { |
(...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
468 if (XGetSelectionOwner(x_display_, selection_name) == x_window_) { | 390 if (XGetSelectionOwner(x_display_, selection_name) == x_window_) { |
469 // We can local fastpath instead of playing the nested message loop game | 391 // We can local fastpath instead of playing the nested message loop game |
470 // with the X server. | 392 // with the X server. |
471 SelectionFormatMap* format_map = LookupStorageForAtom(selection_name); | 393 SelectionFormatMap* format_map = LookupStorageForAtom(selection_name); |
472 DCHECK(format_map); | 394 DCHECK(format_map); |
473 | 395 |
474 for (std::vector< ::Atom>::const_iterator it = types.begin(); | 396 for (std::vector< ::Atom>::const_iterator it = types.begin(); |
475 it != types.end(); ++it) { | 397 it != types.end(); ++it) { |
476 SelectionFormatMap::const_iterator format_map_it = format_map->find(*it); | 398 SelectionFormatMap::const_iterator format_map_it = format_map->find(*it); |
477 if (format_map_it != format_map->end()) { | 399 if (format_map_it != format_map->end()) { |
478 scoped_ptr<SelectionData> data_out(new SelectionData(&atom_cache_)); | 400 scoped_ptr<SelectionData> data_out(new SelectionData(x_display_)); |
479 data_out->Set(format_map_it->first, format_map_it->second.first, | 401 data_out->Set(format_map_it->first, format_map_it->second.first, |
480 format_map_it->second.second, false); | 402 format_map_it->second.second, false); |
481 return data_out.Pass(); | 403 return data_out.Pass(); |
482 } | 404 } |
483 } | 405 } |
484 } else { | 406 } else { |
485 TargetList targets = WaitAndGetTargetsList(buffer); | 407 TargetList targets = WaitAndGetTargetsList(buffer); |
486 SelectionRequestor* receiver = GetSelectionRequestorForBuffer(buffer); | 408 SelectionRequestor* receiver = GetSelectionRequestorForBuffer(buffer); |
487 | 409 |
488 for (std::vector< ::Atom>::const_iterator it = types.begin(); | 410 std::vector< ::Atom> intersection; |
489 it != types.end(); ++it) { | 411 ui::GetAtomIntersection(targets.target_list(), types, &intersection); |
490 unsigned char* data = NULL; | 412 return receiver->RequestAndWaitForTypes(intersection); |
491 size_t data_bytes = 0; | |
492 ::Atom type = None; | |
493 if (targets.ContainsAtom(*it) && | |
494 receiver->PerformBlockingConvertSelection(*it, | |
495 &data, | |
496 &data_bytes, | |
497 NULL, | |
498 &type) && | |
499 type == *it) { | |
500 scoped_ptr<SelectionData> data_out(new SelectionData(&atom_cache_)); | |
501 data_out->Set(type, (char*)data, data_bytes, true); | |
502 return data_out.Pass(); | |
503 } | |
504 } | |
505 } | 413 } |
506 | 414 |
507 return scoped_ptr<SelectionData>(); | 415 return scoped_ptr<SelectionData>(); |
508 } | 416 } |
509 | 417 |
510 TargetList Clipboard::AuraX11Details::WaitAndGetTargetsList( | 418 TargetList Clipboard::AuraX11Details::WaitAndGetTargetsList( |
511 Buffer buffer) { | 419 Buffer buffer) { |
512 ::Atom selection_name = LookupSelectionForBuffer(buffer); | 420 ::Atom selection_name = LookupSelectionForBuffer(buffer); |
513 std::vector< ::Atom> out; | 421 std::vector< ::Atom> out; |
514 if (XGetSelectionOwner(x_display_, selection_name) == x_window_) { | 422 if (XGetSelectionOwner(x_display_, selection_name) == x_window_) { |
(...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
734 if (src_url) | 642 if (src_url) |
735 src_url->clear(); | 643 src_url->clear(); |
736 *fragment_start = 0; | 644 *fragment_start = 0; |
737 *fragment_end = 0; | 645 *fragment_end = 0; |
738 | 646 |
739 scoped_ptr<SelectionData> data(aurax11_details_->RequestAndWaitForTypes( | 647 scoped_ptr<SelectionData> data(aurax11_details_->RequestAndWaitForTypes( |
740 buffer, aurax11_details_->GetAtomsForFormat(GetHtmlFormatType()))); | 648 buffer, aurax11_details_->GetAtomsForFormat(GetHtmlFormatType()))); |
741 if (!data.get()) | 649 if (!data.get()) |
742 return; | 650 return; |
743 | 651 |
744 // If the data starts with 0xFEFF, i.e., Byte Order Mark, assume it is | 652 *markup = data->GetHtml(); |
745 // UTF-16, otherwise assume UTF-8. | |
746 if (data->size() >= 2 && | |
747 reinterpret_cast<const uint16_t*>(data->data())[0] == 0xFEFF) { | |
748 markup->assign(reinterpret_cast<const uint16_t*>(data->data()) + 1, | |
749 (data->size() / 2) - 1); | |
750 } else { | |
751 UTF8ToUTF16(reinterpret_cast<const char*>(data->data()), data->size(), | |
752 markup); | |
753 } | |
754 | |
755 // If there is a terminating NULL, drop it. | |
756 if (!markup->empty() && markup->at(markup->length() - 1) == '\0') | |
757 markup->resize(markup->length() - 1); | |
758 | 653 |
759 *fragment_start = 0; | 654 *fragment_start = 0; |
760 DCHECK(markup->length() <= kuint32max); | 655 DCHECK(markup->length() <= kuint32max); |
761 *fragment_end = static_cast<uint32>(markup->length()); | 656 *fragment_end = static_cast<uint32>(markup->length()); |
762 } | 657 } |
763 | 658 |
764 void Clipboard::ReadRTF(Buffer buffer, std::string* result) const { | 659 void Clipboard::ReadRTF(Buffer buffer, std::string* result) const { |
765 DCHECK(CalledOnValidThread()); | 660 DCHECK(CalledOnValidThread()); |
766 | 661 |
767 scoped_ptr<SelectionData> data(aurax11_details_->RequestAndWaitForTypes( | 662 scoped_ptr<SelectionData> data(aurax11_details_->RequestAndWaitForTypes( |
(...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
980 return type; | 875 return type; |
981 } | 876 } |
982 | 877 |
983 // static | 878 // static |
984 const Clipboard::FormatType& Clipboard::GetSourceTagFormatType() { | 879 const Clipboard::FormatType& Clipboard::GetSourceTagFormatType() { |
985 CR_DEFINE_STATIC_LOCAL(FormatType, type, (kSourceTagType)); | 880 CR_DEFINE_STATIC_LOCAL(FormatType, type, (kSourceTagType)); |
986 return type; | 881 return type; |
987 } | 882 } |
988 | 883 |
989 } // namespace ui | 884 } // namespace ui |
OLD | NEW |