| 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 |