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 3// found in the LICENSE file. 4 5#include "ui/base/clipboard/clipboard.h" 6 7#include <X11/extensions/Xfixes.h> 8#include <X11/Xatom.h> 9#include <list> 10#include <set> 11 12#include "base/basictypes.h" 13#include "base/files/file_path.h" 14#include "base/logging.h" 15#include "base/memory/ref_counted_memory.h" 16#include "base/memory/scoped_ptr.h" 17#include "base/memory/singleton.h" 18#include "base/metrics/histogram.h" 19#include "base/stl_util.h" 20#include "base/strings/utf_string_conversions.h" 21#include "third_party/skia/include/core/SkBitmap.h" 22#include "ui/base/clipboard/custom_data_helper.h" 23#include "ui/base/x/selection_owner.h" 24#include "ui/base/x/selection_requestor.h" 25#include "ui/base/x/selection_utils.h" 26#include "ui/base/x/x11_util.h" 27#include "ui/events/platform/platform_event_dispatcher.h" 28#include "ui/events/platform/platform_event_observer.h" 29#include "ui/events/platform/platform_event_source.h" 30#include "ui/gfx/codec/png_codec.h" 31#include "ui/gfx/size.h" 32#include "ui/gfx/x/x11_atom_cache.h" 33 34namespace ui { 35 36namespace { 37 38const char kClipboard[] = "CLIPBOARD"; 39const char kClipboardManager[] = "CLIPBOARD_MANAGER"; 40const char kMimeTypeFilename[] = "chromium/filename"; 41const char kMimeTypePepperCustomData[] = "chromium/x-pepper-custom-data"; 42const char kMimeTypeWebkitSmartPaste[] = "chromium/x-webkit-paste"; 43const char kSaveTargets[] = "SAVE_TARGETS"; 44const char kTargets[] = "TARGETS"; 45 46const char* kAtomsToCache[] = { 47 kClipboard, 48 kClipboardManager, 49 Clipboard::kMimeTypePNG, 50 kMimeTypeFilename, 51 kMimeTypeMozillaURL, 52 kMimeTypeWebkitSmartPaste, 53 kSaveTargets, 54 kString, 55 kTargets, 56 kText, 57 kUtf8String, 58 NULL 59}; 60 61/////////////////////////////////////////////////////////////////////////////// 62 63// Uses the XFixes API to provide sequence numbers for GetSequenceNumber(). 64class SelectionChangeObserver : public ui::PlatformEventObserver { 65 public: 66 static SelectionChangeObserver* GetInstance(); 67 68 uint64 clipboard_sequence_number() const { 69 return clipboard_sequence_number_; 70 } 71 uint64 primary_sequence_number() const { return primary_sequence_number_; } 72 73 private: 74 friend struct DefaultSingletonTraits<SelectionChangeObserver>; 75 76 SelectionChangeObserver(); 77 virtual ~SelectionChangeObserver(); 78 79 // ui::PlatformEventObserver: 80 virtual void WillProcessEvent(const ui::PlatformEvent& event) OVERRIDE; 81 virtual void DidProcessEvent(const ui::PlatformEvent& event) OVERRIDE {} 82 83 int event_base_; 84 Atom clipboard_atom_; 85 uint64 clipboard_sequence_number_; 86 uint64 primary_sequence_number_; 87 88 DISALLOW_COPY_AND_ASSIGN(SelectionChangeObserver); 89}; 90 91SelectionChangeObserver::SelectionChangeObserver() 92 : event_base_(-1), 93 clipboard_atom_(None), 94 clipboard_sequence_number_(0), 95 primary_sequence_number_(0) { 96 int ignored; 97 if (XFixesQueryExtension(gfx::GetXDisplay(), &event_base_, &ignored)) { 98 clipboard_atom_ = XInternAtom(gfx::GetXDisplay(), kClipboard, false); 99 XFixesSelectSelectionInput(gfx::GetXDisplay(), GetX11RootWindow(), 100 clipboard_atom_, 101 XFixesSetSelectionOwnerNotifyMask | 102 XFixesSelectionWindowDestroyNotifyMask | 103 XFixesSelectionClientCloseNotifyMask); 104 // This seems to be semi-optional. For some reason, registering for any 105 // selection notify events seems to subscribe us to events for both the 106 // primary and the clipboard buffers. Register anyway just to be safe. 107 XFixesSelectSelectionInput(gfx::GetXDisplay(), GetX11RootWindow(), 108 XA_PRIMARY, 109 XFixesSetSelectionOwnerNotifyMask | 110 XFixesSelectionWindowDestroyNotifyMask | 111 XFixesSelectionClientCloseNotifyMask); 112 113 ui::PlatformEventSource::GetInstance()->AddPlatformEventObserver(this); 114 } 115} 116 117SelectionChangeObserver::~SelectionChangeObserver() { 118 // We are a singleton; we will outlive the event source. 119} 120 121SelectionChangeObserver* SelectionChangeObserver::GetInstance() { 122 return Singleton<SelectionChangeObserver>::get(); 123} 124 125void SelectionChangeObserver::WillProcessEvent(const ui::PlatformEvent& event) { 126 if (event->type == event_base_ + XFixesSelectionNotify) { 127 XFixesSelectionNotifyEvent* ev = 128 reinterpret_cast<XFixesSelectionNotifyEvent*>(event); 129 if (ev->selection == clipboard_atom_) { 130 clipboard_sequence_number_++; 131 } else if (ev->selection == XA_PRIMARY) { 132 primary_sequence_number_++; 133 } else { 134 DLOG(ERROR) << "Unexpected selection atom: " << ev->selection; 135 } 136 } 137} 138 139/////////////////////////////////////////////////////////////////////////////// 140 141// Represents a list of possible return types. Copy constructable. 142class TargetList { 143 public: 144 typedef std::vector< ::Atom> AtomVector; 145 146 TargetList(const AtomVector& target_list, X11AtomCache* atom_cache); 147 148 const AtomVector& target_list() { return target_list_; } 149 150 bool ContainsText() const; 151 bool ContainsFormat(const Clipboard::FormatType& format_type) const; 152 bool ContainsAtom(::Atom atom) const; 153 154 private: 155 AtomVector target_list_; 156 X11AtomCache* atom_cache_; 157}; 158 159TargetList::TargetList(const AtomVector& target_list, 160 X11AtomCache* atom_cache) 161 : target_list_(target_list), 162 atom_cache_(atom_cache) { 163} 164 165bool TargetList::ContainsText() const { 166 std::vector< ::Atom> atoms = GetTextAtomsFrom(atom_cache_); 167 for (std::vector< ::Atom>::const_iterator it = atoms.begin(); 168 it != atoms.end(); ++it) { 169 if (ContainsAtom(*it)) 170 return true; 171 } 172 173 return false; 174} 175 176bool TargetList::ContainsFormat( 177 const Clipboard::FormatType& format_type) const { 178 ::Atom atom = atom_cache_->GetAtom(format_type.ToString().c_str()); 179 return ContainsAtom(atom); 180} 181 182bool TargetList::ContainsAtom(::Atom atom) const { 183 return find(target_list_.begin(), target_list_.end(), atom) 184 != target_list_.end(); 185} 186 187} // namespace 188 189/////////////////////////////////////////////////////////////////////////////// 190 191// I would love for the FormatType to really be a wrapper around an X11 ::Atom, 192// but there are a few problems. Chromeos unit tests spawn a new X11 server for 193// each test, so Atom numeric values don't persist across tests. We could still 194// maybe deal with that if we didn't have static accessor methods everywhere. 195 196Clipboard::FormatType::FormatType() { 197} 198 199Clipboard::FormatType::FormatType(const std::string& native_format) 200 : data_(native_format) { 201} 202 203Clipboard::FormatType::~FormatType() { 204} 205 206std::string Clipboard::FormatType::Serialize() const { 207 return data_; 208} 209 210// static 211Clipboard::FormatType Clipboard::FormatType::Deserialize( 212 const std::string& serialization) { 213 return FormatType(serialization); 214} 215 216bool Clipboard::FormatType::operator<(const FormatType& other) const { 217 return data_ < other.data_; 218} 219 220bool Clipboard::FormatType::Equals(const FormatType& other) const { 221 return data_ == other.data_; 222} 223 224/////////////////////////////////////////////////////////////////////////////// 225// Clipboard::AuraX11Details 226 227// Private implementation of our X11 integration. Keeps X11 headers out of the 228// majority of chrome, which break badly. 229class Clipboard::AuraX11Details : public PlatformEventDispatcher { 230 public: 231 AuraX11Details(); 232 virtual ~AuraX11Details(); 233 234 X11AtomCache* atom_cache() { return &atom_cache_; } 235 236 // Returns the X11 type that we pass to various XSelection functions for the 237 // given type. 238 ::Atom LookupSelectionForClipboardType(ClipboardType type) const; 239 240 // Returns the X11 type that we pass to various XSelection functions for 241 // CLIPBOARD_TYPE_COPY_PASTE. 242 ::Atom GetCopyPasteSelection() const; 243 244 // Finds the SelectionFormatMap for the incoming selection atom. 245 const SelectionFormatMap& LookupStorageForAtom(::Atom atom); 246 247 // As we need to collect all the data types before we tell X11 that we own a 248 // particular selection, we create a temporary clipboard mapping that 249 // InsertMapping writes to. Then we commit it in TakeOwnershipOfSelection, 250 // where we save it in one of the clipboard data slots. 251 void CreateNewClipboardData(); 252 253 // Inserts a mapping into clipboard_data_. 254 void InsertMapping(const std::string& key, 255 const scoped_refptr<base::RefCountedMemory>& memory); 256 257 // Moves the temporary |clipboard_data_| to the long term data storage for 258 // |type|. 259 void TakeOwnershipOfSelection(ClipboardType type); 260 261 // Returns the first of |types| offered by the current selection holder in 262 // |data_out|, or returns NULL if none of those types are available. 263 // 264 // If the selection holder is us, this call is synchronous and we pull 265 // the data out of |clipboard_selection_| or |primary_selection_|. If the 266 // selection holder is some other window, we spin up a nested message loop 267 // and do the asynchronous dance with whatever application is holding the 268 // selection. 269 ui::SelectionData RequestAndWaitForTypes(ClipboardType type, 270 const std::vector< ::Atom>& types); 271 272 // Retrieves the list of possible data types the current clipboard owner has. 273 // 274 // If the selection holder is us, this is synchronous, otherwise this runs a 275 // blocking message loop. 276 TargetList WaitAndGetTargetsList(ClipboardType type); 277 278 // Returns a list of all text atoms that we handle. 279 std::vector< ::Atom> GetTextAtoms() const; 280 281 // Returns a vector with a |format| converted to an X11 atom. 282 std::vector< ::Atom> GetAtomsForFormat(const Clipboard::FormatType& format); 283 284 // Clears a certain clipboard type, whether we own it or not. 285 void Clear(ClipboardType type); 286 287 // If we own the CLIPBOARD selection, requests the clipboard manager to take 288 // ownership of it. 289 void StoreCopyPasteDataAndWait(); 290 291 private: 292 // PlatformEventDispatcher: 293 virtual bool CanDispatchEvent(const PlatformEvent& event) OVERRIDE; 294 virtual uint32_t DispatchEvent(const PlatformEvent& event) OVERRIDE; 295 296 // Our X11 state. 297 Display* x_display_; 298 ::Window x_root_window_; 299 300 // Input-only window used as a selection owner. 301 ::Window x_window_; 302 303 X11AtomCache atom_cache_; 304 305 // Object which requests and receives selection data. 306 SelectionRequestor selection_requestor_; 307 308 // Temporary target map that we write to during DispatchObects. 309 SelectionFormatMap clipboard_data_; 310 311 // Objects which offer selection data to other windows. 312 SelectionOwner clipboard_owner_; 313 SelectionOwner primary_owner_; 314 315 DISALLOW_COPY_AND_ASSIGN(AuraX11Details); 316}; 317 318Clipboard::AuraX11Details::AuraX11Details() 319 : x_display_(gfx::GetXDisplay()), 320 x_root_window_(DefaultRootWindow(x_display_)), 321 x_window_(XCreateWindow( 322 x_display_, x_root_window_, 323 -100, -100, 10, 10, // x, y, width, height 324 0, // border width 325 CopyFromParent, // depth 326 InputOnly, 327 CopyFromParent, // visual 328 0, 329 NULL)), 330 atom_cache_(x_display_, kAtomsToCache), 331 selection_requestor_(x_display_, x_window_, this), 332 clipboard_owner_(x_display_, x_window_, atom_cache_.GetAtom(kClipboard)), 333 primary_owner_(x_display_, x_window_, XA_PRIMARY) { 334 // We don't know all possible MIME types at compile time. 335 atom_cache_.allow_uncached_atoms(); 336 337 XStoreName(x_display_, x_window_, "Chromium clipboard"); 338 XSelectInput(x_display_, x_window_, PropertyChangeMask); 339 340 if (PlatformEventSource::GetInstance()) 341 PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this); 342} 343 344Clipboard::AuraX11Details::~AuraX11Details() { 345 if (PlatformEventSource::GetInstance()) 346 PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this); 347 348 XDestroyWindow(x_display_, x_window_); 349} 350 351::Atom Clipboard::AuraX11Details::LookupSelectionForClipboardType( 352 ClipboardType type) const { 353 if (type == CLIPBOARD_TYPE_COPY_PASTE) 354 return GetCopyPasteSelection(); 355 356 return XA_PRIMARY; 357} 358 359::Atom Clipboard::AuraX11Details::GetCopyPasteSelection() const { 360 return atom_cache_.GetAtom(kClipboard); 361} 362 363const SelectionFormatMap& Clipboard::AuraX11Details::LookupStorageForAtom( 364 ::Atom atom) { 365 if (atom == XA_PRIMARY) 366 return primary_owner_.selection_format_map(); 367 368 DCHECK_EQ(GetCopyPasteSelection(), atom); 369 return clipboard_owner_.selection_format_map(); 370} 371 372void Clipboard::AuraX11Details::CreateNewClipboardData() { 373 clipboard_data_ = SelectionFormatMap(); 374} 375 376void Clipboard::AuraX11Details::InsertMapping( 377 const std::string& key, 378 const scoped_refptr<base::RefCountedMemory>& memory) { 379 ::Atom atom_key = atom_cache_.GetAtom(key.c_str()); 380 clipboard_data_.Insert(atom_key, memory); 381} 382 383void Clipboard::AuraX11Details::TakeOwnershipOfSelection(ClipboardType type) { 384 if (type == CLIPBOARD_TYPE_COPY_PASTE) 385 return clipboard_owner_.TakeOwnershipOfSelection(clipboard_data_); 386 else 387 return primary_owner_.TakeOwnershipOfSelection(clipboard_data_); 388} 389 390SelectionData Clipboard::AuraX11Details::RequestAndWaitForTypes( 391 ClipboardType type, 392 const std::vector< ::Atom>& types) { 393 ::Atom selection_name = LookupSelectionForClipboardType(type); 394 if (XGetSelectionOwner(x_display_, selection_name) == x_window_) { 395 // We can local fastpath instead of playing the nested message loop game 396 // with the X server. 397 const SelectionFormatMap& format_map = LookupStorageForAtom(selection_name); 398 399 for (std::vector< ::Atom>::const_iterator it = types.begin(); 400 it != types.end(); ++it) { 401 SelectionFormatMap::const_iterator format_map_it = format_map.find(*it); 402 if (format_map_it != format_map.end()) 403 return SelectionData(format_map_it->first, format_map_it->second); 404 } 405 } else { 406 TargetList targets = WaitAndGetTargetsList(type); 407 408 ::Atom selection_name = LookupSelectionForClipboardType(type); 409 std::vector< ::Atom> intersection; 410 ui::GetAtomIntersection(types, targets.target_list(), &intersection); 411 return selection_requestor_.RequestAndWaitForTypes(selection_name, 412 intersection); 413 } 414 415 return SelectionData(); 416} 417 418TargetList Clipboard::AuraX11Details::WaitAndGetTargetsList( 419 ClipboardType type) { 420 ::Atom selection_name = LookupSelectionForClipboardType(type); 421 std::vector< ::Atom> out; 422 if (XGetSelectionOwner(x_display_, selection_name) == x_window_) { 423 // We can local fastpath and return the list of local targets. 424 const SelectionFormatMap& format_map = LookupStorageForAtom(selection_name); 425 426 for (SelectionFormatMap::const_iterator it = format_map.begin(); 427 it != format_map.end(); ++it) { 428 out.push_back(it->first); 429 } 430 } else { 431 scoped_refptr<base::RefCountedMemory> data; 432 size_t out_data_items = 0; 433 ::Atom out_type = None; 434 435 if (selection_requestor_.PerformBlockingConvertSelection( 436 selection_name, 437 atom_cache_.GetAtom(kTargets), 438 &data, 439 &out_data_items, 440 &out_type)) { 441 // Some apps return an |out_type| of "TARGETS". (crbug.com/377893) 442 if (out_type == XA_ATOM || out_type == atom_cache_.GetAtom(kTargets)) { 443 const ::Atom* atom_array = 444 reinterpret_cast<const ::Atom*>(data->front()); 445 for (size_t i = 0; i < out_data_items; ++i) 446 out.push_back(atom_array[i]); 447 } 448 } else { 449 // There was no target list. Most Java apps doesn't offer a TARGETS list, 450 // even though they AWT to. They will offer individual text types if you 451 // ask. If this is the case we attempt to make sense of the contents as 452 // text. This is pretty unfortunate since it means we have to actually 453 // copy the data to see if it is available, but at least this path 454 // shouldn't be hit for conforming programs. 455 std::vector< ::Atom> types = GetTextAtoms(); 456 for (std::vector< ::Atom>::const_iterator it = types.begin(); 457 it != types.end(); ++it) { 458 ::Atom type = None; 459 if (selection_requestor_.PerformBlockingConvertSelection(selection_name, 460 *it, 461 NULL, 462 NULL, 463 &type) && 464 type == *it) { 465 out.push_back(*it); 466 } 467 } 468 } 469 } 470 471 return TargetList(out, &atom_cache_); 472} 473 474std::vector< ::Atom> Clipboard::AuraX11Details::GetTextAtoms() const { 475 return GetTextAtomsFrom(&atom_cache_); 476} 477 478std::vector< ::Atom> Clipboard::AuraX11Details::GetAtomsForFormat( 479 const Clipboard::FormatType& format) { 480 std::vector< ::Atom> atoms; 481 atoms.push_back(atom_cache_.GetAtom(format.ToString().c_str())); 482 return atoms; 483} 484 485void Clipboard::AuraX11Details::Clear(ClipboardType type) { 486 if (type == CLIPBOARD_TYPE_COPY_PASTE) 487 clipboard_owner_.ClearSelectionOwner(); 488 else 489 primary_owner_.ClearSelectionOwner(); 490} 491 492void Clipboard::AuraX11Details::StoreCopyPasteDataAndWait() { 493 ::Atom selection = GetCopyPasteSelection(); 494 if (XGetSelectionOwner(x_display_, selection) != x_window_) 495 return; 496 497 ::Atom clipboard_manager_atom = atom_cache_.GetAtom(kClipboardManager); 498 if (XGetSelectionOwner(x_display_, clipboard_manager_atom) == None) 499 return; 500 501 const SelectionFormatMap& format_map = LookupStorageForAtom(selection); 502 if (format_map.size() == 0) 503 return; 504 std::vector<Atom> targets = format_map.GetTypes(); 505 506 base::TimeTicks start = base::TimeTicks::Now(); 507 selection_requestor_.PerformBlockingConvertSelectionWithParameter( 508 atom_cache_.GetAtom(kClipboardManager), 509 atom_cache_.GetAtom(kSaveTargets), 510 targets); 511 UMA_HISTOGRAM_TIMES("Clipboard.X11StoreCopyPasteDuration", 512 base::TimeTicks::Now() - start); 513} 514 515bool Clipboard::AuraX11Details::CanDispatchEvent(const PlatformEvent& event) { 516 if (event->xany.window == x_window_) 517 return true; 518 519 if (event->type == PropertyNotify) { 520 return primary_owner_.CanDispatchPropertyEvent(*event) || 521 clipboard_owner_.CanDispatchPropertyEvent(*event) || 522 selection_requestor_.CanDispatchPropertyEvent(*event); 523 } 524 return false; 525} 526 527uint32_t Clipboard::AuraX11Details::DispatchEvent(const PlatformEvent& xev) { 528 switch (xev->type) { 529 case SelectionRequest: { 530 if (xev->xselectionrequest.selection == XA_PRIMARY) { 531 primary_owner_.OnSelectionRequest(*xev); 532 } else { 533 // We should not get requests for the CLIPBOARD_MANAGER selection 534 // because we never take ownership of it. 535 DCHECK_EQ(GetCopyPasteSelection(), xev->xselectionrequest.selection); 536 clipboard_owner_.OnSelectionRequest(*xev); 537 } 538 break; 539 } 540 case SelectionNotify: { 541 selection_requestor_.OnSelectionNotify(*xev); 542 break; 543 } 544 case SelectionClear: { 545 if (xev->xselectionclear.selection == XA_PRIMARY) { 546 primary_owner_.OnSelectionClear(*xev); 547 } else { 548 // We should not get requests for the CLIPBOARD_MANAGER selection 549 // because we never take ownership of it. 550 DCHECK_EQ(GetCopyPasteSelection(), xev->xselection.selection); 551 clipboard_owner_.OnSelectionClear(*xev); 552 } 553 break; 554 } 555 case PropertyNotify: { 556 if (primary_owner_.CanDispatchPropertyEvent(*xev)) 557 primary_owner_.OnPropertyEvent(*xev); 558 if (clipboard_owner_.CanDispatchPropertyEvent(*xev)) 559 clipboard_owner_.OnPropertyEvent(*xev); 560 if (selection_requestor_.CanDispatchPropertyEvent(*xev)) 561 selection_requestor_.OnPropertyEvent(*xev); 562 break; 563 } 564 default: 565 break; 566 } 567 568 return POST_DISPATCH_NONE; 569} 570 571/////////////////////////////////////////////////////////////////////////////// 572// Clipboard 573 574Clipboard::Clipboard() 575 : aurax11_details_(new AuraX11Details) { 576 DCHECK(CalledOnValidThread()); 577} 578 579Clipboard::~Clipboard() { 580 DCHECK(CalledOnValidThread()); 581 582 aurax11_details_->StoreCopyPasteDataAndWait(); 583} 584 585void Clipboard::WriteObjects(ClipboardType type, const ObjectMap& objects) { 586 DCHECK(CalledOnValidThread()); 587 DCHECK(IsSupportedClipboardType(type)); 588 589 aurax11_details_->CreateNewClipboardData(); 590 for (ObjectMap::const_iterator iter = objects.begin(); 591 iter != objects.end(); ++iter) { 592 DispatchObject(static_cast<ObjectType>(iter->first), iter->second); 593 } 594 aurax11_details_->TakeOwnershipOfSelection(type); 595 596 if (type == CLIPBOARD_TYPE_COPY_PASTE) { 597 ObjectMap::const_iterator text_iter = objects.find(CBF_TEXT); 598 if (text_iter != objects.end()) { 599 aurax11_details_->CreateNewClipboardData(); 600 const ObjectMapParams& params_vector = text_iter->second; 601 if (params_vector.size()) { 602 const ObjectMapParam& char_vector = params_vector[0]; 603 if (char_vector.size()) 604 WriteText(&char_vector.front(), char_vector.size()); 605 } 606 aurax11_details_->TakeOwnershipOfSelection(CLIPBOARD_TYPE_SELECTION); 607 } 608 } 609} 610 611bool Clipboard::IsFormatAvailable(const FormatType& format, 612 ClipboardType type) const { 613 DCHECK(CalledOnValidThread()); 614 DCHECK(IsSupportedClipboardType(type)); 615 616 TargetList target_list = aurax11_details_->WaitAndGetTargetsList(type); 617 if (format.Equals(GetPlainTextFormatType()) || 618 format.Equals(GetUrlFormatType())) { 619 return target_list.ContainsText(); 620 } 621 return target_list.ContainsFormat(format); 622} 623 624void Clipboard::Clear(ClipboardType type) { 625 DCHECK(CalledOnValidThread()); 626 DCHECK(IsSupportedClipboardType(type)); 627 aurax11_details_->Clear(type); 628} 629 630void Clipboard::ReadAvailableTypes(ClipboardType type, 631 std::vector<base::string16>* types, 632 bool* contains_filenames) const { 633 DCHECK(CalledOnValidThread()); 634 if (!types || !contains_filenames) { 635 NOTREACHED(); 636 return; 637 } 638 639 TargetList target_list = aurax11_details_->WaitAndGetTargetsList(type); 640 641 types->clear(); 642 643 if (target_list.ContainsText()) 644 types->push_back(base::UTF8ToUTF16(kMimeTypeText)); 645 if (target_list.ContainsFormat(GetHtmlFormatType())) 646 types->push_back(base::UTF8ToUTF16(kMimeTypeHTML)); 647 if (target_list.ContainsFormat(GetRtfFormatType())) 648 types->push_back(base::UTF8ToUTF16(kMimeTypeRTF)); 649 if (target_list.ContainsFormat(GetBitmapFormatType())) 650 types->push_back(base::UTF8ToUTF16(kMimeTypePNG)); 651 *contains_filenames = false; 652 653 SelectionData data(aurax11_details_->RequestAndWaitForTypes( 654 type, aurax11_details_->GetAtomsForFormat(GetWebCustomDataFormatType()))); 655 if (data.IsValid()) 656 ReadCustomDataTypes(data.GetData(), data.GetSize(), types); 657} 658 659void Clipboard::ReadText(ClipboardType type, base::string16* result) const { 660 DCHECK(CalledOnValidThread()); 661 662 SelectionData data(aurax11_details_->RequestAndWaitForTypes( 663 type, aurax11_details_->GetTextAtoms())); 664 if (data.IsValid()) { 665 std::string text = data.GetText(); 666 *result = base::UTF8ToUTF16(text); 667 } 668} 669 670void Clipboard::ReadAsciiText(ClipboardType type, std::string* result) const { 671 DCHECK(CalledOnValidThread()); 672 673 SelectionData data(aurax11_details_->RequestAndWaitForTypes( 674 type, aurax11_details_->GetTextAtoms())); 675 if (data.IsValid()) 676 result->assign(data.GetText()); 677} 678 679// TODO(estade): handle different charsets. 680// TODO(port): set *src_url. 681void Clipboard::ReadHTML(ClipboardType type, 682 base::string16* markup, 683 std::string* src_url, 684 uint32* fragment_start, 685 uint32* fragment_end) const { 686 DCHECK(CalledOnValidThread()); 687 markup->clear(); 688 if (src_url) 689 src_url->clear(); 690 *fragment_start = 0; 691 *fragment_end = 0; 692 693 SelectionData data(aurax11_details_->RequestAndWaitForTypes( 694 type, aurax11_details_->GetAtomsForFormat(GetHtmlFormatType()))); 695 if (data.IsValid()) { 696 *markup = data.GetHtml(); 697 698 *fragment_start = 0; 699 DCHECK(markup->length() <= kuint32max); 700 *fragment_end = static_cast<uint32>(markup->length()); 701 } 702} 703 704void Clipboard::ReadRTF(ClipboardType type, std::string* result) const { 705 DCHECK(CalledOnValidThread()); 706 707 SelectionData data(aurax11_details_->RequestAndWaitForTypes( 708 type, aurax11_details_->GetAtomsForFormat(GetRtfFormatType()))); 709 if (data.IsValid()) 710 data.AssignTo(result); 711} 712 713SkBitmap Clipboard::ReadImage(ClipboardType type) const { 714 DCHECK(CalledOnValidThread()); 715 716 SelectionData data(aurax11_details_->RequestAndWaitForTypes( 717 type, aurax11_details_->GetAtomsForFormat(GetBitmapFormatType()))); 718 if (data.IsValid()) { 719 SkBitmap bitmap; 720 if (gfx::PNGCodec::Decode(data.GetData(), data.GetSize(), &bitmap)) 721 return SkBitmap(bitmap); 722 } 723 724 return SkBitmap(); 725} 726 727void Clipboard::ReadCustomData(ClipboardType clipboard_type, 728 const base::string16& type, 729 base::string16* result) const { 730 DCHECK(CalledOnValidThread()); 731 732 SelectionData data(aurax11_details_->RequestAndWaitForTypes( 733 clipboard_type, 734 aurax11_details_->GetAtomsForFormat(GetWebCustomDataFormatType()))); 735 if (data.IsValid()) 736 ReadCustomDataForType(data.GetData(), data.GetSize(), type, result); 737} 738 739void Clipboard::ReadBookmark(base::string16* title, std::string* url) const { 740 DCHECK(CalledOnValidThread()); 741 // TODO(erg): This was left NOTIMPLEMENTED() in the gtk port too. 742 NOTIMPLEMENTED(); 743} 744 745void Clipboard::ReadData(const FormatType& format, std::string* result) const { 746 DCHECK(CalledOnValidThread()); 747 748 SelectionData data(aurax11_details_->RequestAndWaitForTypes( 749 CLIPBOARD_TYPE_COPY_PASTE, aurax11_details_->GetAtomsForFormat(format))); 750 if (data.IsValid()) 751 data.AssignTo(result); 752} 753 754uint64 Clipboard::GetSequenceNumber(ClipboardType type) { 755 DCHECK(CalledOnValidThread()); 756 if (type == CLIPBOARD_TYPE_COPY_PASTE) 757 return SelectionChangeObserver::GetInstance()->clipboard_sequence_number(); 758 else 759 return SelectionChangeObserver::GetInstance()->primary_sequence_number(); 760} 761 762void Clipboard::WriteText(const char* text_data, size_t text_len) { 763 std::string str(text_data, text_len); 764 scoped_refptr<base::RefCountedMemory> mem( 765 base::RefCountedString::TakeString(&str)); 766 767 aurax11_details_->InsertMapping(kMimeTypeText, mem); 768 aurax11_details_->InsertMapping(kText, mem); 769 aurax11_details_->InsertMapping(kString, mem); 770 aurax11_details_->InsertMapping(kUtf8String, mem); 771} 772 773void Clipboard::WriteHTML(const char* markup_data, 774 size_t markup_len, 775 const char* url_data, 776 size_t url_len) { 777 // TODO(estade): We need to expand relative links with |url_data|. 778 static const char* html_prefix = "<meta http-equiv=\"content-type\" " 779 "content=\"text/html; charset=utf-8\">"; 780 std::string data = html_prefix; 781 data += std::string(markup_data, markup_len); 782 // Some programs expect NULL-terminated data. See http://crbug.com/42624 783 data += '\0'; 784 785 scoped_refptr<base::RefCountedMemory> mem( 786 base::RefCountedString::TakeString(&data)); 787 aurax11_details_->InsertMapping(kMimeTypeHTML, mem); 788} 789 790void Clipboard::WriteRTF(const char* rtf_data, size_t data_len) { 791 WriteData(GetRtfFormatType(), rtf_data, data_len); 792} 793 794void Clipboard::WriteBookmark(const char* title_data, 795 size_t title_len, 796 const char* url_data, 797 size_t url_len) { 798 // Write as a mozilla url (UTF16: URL, newline, title). 799 base::string16 url = base::UTF8ToUTF16(std::string(url_data, url_len) + "\n"); 800 base::string16 title = base::UTF8ToUTF16(std::string(title_data, title_len)); 801 802 std::vector<unsigned char> data; 803 ui::AddString16ToVector(url, &data); 804 ui::AddString16ToVector(title, &data); 805 scoped_refptr<base::RefCountedMemory> mem( 806 base::RefCountedBytes::TakeVector(&data)); 807 808 aurax11_details_->InsertMapping(kMimeTypeMozillaURL, mem); 809} 810 811// Write an extra flavor that signifies WebKit was the last to modify the 812// pasteboard. This flavor has no data. 813void Clipboard::WriteWebSmartPaste() { 814 std::string empty; 815 aurax11_details_->InsertMapping( 816 kMimeTypeWebkitSmartPaste, 817 scoped_refptr<base::RefCountedMemory>( 818 base::RefCountedString::TakeString(&empty))); 819} 820 821void Clipboard::WriteBitmap(const SkBitmap& bitmap) { 822 // Encode the bitmap as a PNG for transport. 823 std::vector<unsigned char> output; 824 if (gfx::PNGCodec::FastEncodeBGRASkBitmap(bitmap, false, &output)) { 825 aurax11_details_->InsertMapping(kMimeTypePNG, 826 base::RefCountedBytes::TakeVector( 827 &output)); 828 } 829} 830 831void Clipboard::WriteData(const FormatType& format, 832 const char* data_data, 833 size_t data_len) { 834 // We assume that certain mapping types are only written by trusted code. 835 // Therefore we must upkeep their integrity. 836 if (format.Equals(GetBitmapFormatType())) 837 return; 838 839 std::vector<unsigned char> bytes(data_data, data_data + data_len); 840 scoped_refptr<base::RefCountedMemory> mem( 841 base::RefCountedBytes::TakeVector(&bytes)); 842 aurax11_details_->InsertMapping(format.ToString(), mem); 843} 844 845// static 846Clipboard::FormatType Clipboard::GetFormatType( 847 const std::string& format_string) { 848 return FormatType::Deserialize(format_string); 849} 850 851// static 852const Clipboard::FormatType& Clipboard::GetUrlFormatType() { 853 CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeURIList)); 854 return type; 855} 856 857// static 858const Clipboard::FormatType& Clipboard::GetUrlWFormatType() { 859 return GetUrlFormatType(); 860} 861 862// static 863const Clipboard::FormatType& Clipboard::GetPlainTextFormatType() { 864 CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeText)); 865 return type; 866} 867 868// static 869const Clipboard::FormatType& Clipboard::GetPlainTextWFormatType() { 870 return GetPlainTextFormatType(); 871} 872 873// static 874const Clipboard::FormatType& Clipboard::GetFilenameFormatType() { 875 CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeFilename)); 876 return type; 877} 878 879// static 880const Clipboard::FormatType& Clipboard::GetFilenameWFormatType() { 881 return Clipboard::GetFilenameFormatType(); 882} 883 884// static 885const Clipboard::FormatType& Clipboard::GetHtmlFormatType() { 886 CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeHTML)); 887 return type; 888} 889 890// static 891const Clipboard::FormatType& Clipboard::GetRtfFormatType() { 892 CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeRTF)); 893 return type; 894} 895 896// static 897const Clipboard::FormatType& Clipboard::GetBitmapFormatType() { 898 CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypePNG)); 899 return type; 900} 901 902// static 903const Clipboard::FormatType& Clipboard::GetWebKitSmartPasteFormatType() { 904 CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeWebkitSmartPaste)); 905 return type; 906} 907 908// static 909const Clipboard::FormatType& Clipboard::GetWebCustomDataFormatType() { 910 CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeWebCustomData)); 911 return type; 912} 913 914// static 915const Clipboard::FormatType& Clipboard::GetPepperCustomDataFormatType() { 916 CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypePepperCustomData)); 917 return type; 918} 919 920} // namespace ui 921