Drive: Add BatchableRequest subclass.
[chromium-blink-merge.git] / ui / base / clipboard / clipboard_aurax11.cc
blobde56858dffc786d21baf0ec03285ade20e03e69c
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.
5 #include "ui/base/clipboard/clipboard_aurax11.h"
7 #include <X11/extensions/Xfixes.h>
8 #include <X11/Xatom.h>
9 #include <list>
10 #include <set>
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/geometry/size.h"
32 #include "ui/gfx/x/x11_atom_cache.h"
34 namespace ui {
36 namespace {
38 const char kClipboard[] = "CLIPBOARD";
39 const char kClipboardManager[] = "CLIPBOARD_MANAGER";
40 const char kMimeTypeFilename[] = "chromium/filename";
41 const char kMimeTypePepperCustomData[] = "chromium/x-pepper-custom-data";
42 const char kMimeTypeWebkitSmartPaste[] = "chromium/x-webkit-paste";
43 const char kSaveTargets[] = "SAVE_TARGETS";
44 const char kTargets[] = "TARGETS";
46 const 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
61 ///////////////////////////////////////////////////////////////////////////////
63 // Uses the XFixes API to provide sequence numbers for GetSequenceNumber().
64 class SelectionChangeObserver : public ui::PlatformEventObserver {
65 public:
66 static SelectionChangeObserver* GetInstance();
68 uint64 clipboard_sequence_number() const {
69 return clipboard_sequence_number_;
71 uint64 primary_sequence_number() const { return primary_sequence_number_; }
73 private:
74 friend struct DefaultSingletonTraits<SelectionChangeObserver>;
76 SelectionChangeObserver();
77 ~SelectionChangeObserver() override;
79 // ui::PlatformEventObserver:
80 void WillProcessEvent(const ui::PlatformEvent& event) override;
81 void DidProcessEvent(const ui::PlatformEvent& event) override {}
83 int event_base_;
84 Atom clipboard_atom_;
85 uint64 clipboard_sequence_number_;
86 uint64 primary_sequence_number_;
88 DISALLOW_COPY_AND_ASSIGN(SelectionChangeObserver);
91 SelectionChangeObserver::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);
113 ui::PlatformEventSource::GetInstance()->AddPlatformEventObserver(this);
117 SelectionChangeObserver::~SelectionChangeObserver() {
118 // We are a singleton; we will outlive the event source.
121 SelectionChangeObserver* SelectionChangeObserver::GetInstance() {
122 return Singleton<SelectionChangeObserver>::get();
125 void 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;
139 ///////////////////////////////////////////////////////////////////////////////
141 // Represents a list of possible return types. Copy constructable.
142 class TargetList {
143 public:
144 typedef std::vector< ::Atom> AtomVector;
146 TargetList(const AtomVector& target_list, X11AtomCache* atom_cache);
148 const AtomVector& target_list() { return target_list_; }
150 bool ContainsText() const;
151 bool ContainsFormat(const Clipboard::FormatType& format_type) const;
152 bool ContainsAtom(::Atom atom) const;
154 private:
155 AtomVector target_list_;
156 X11AtomCache* atom_cache_;
159 TargetList::TargetList(const AtomVector& target_list,
160 X11AtomCache* atom_cache)
161 : target_list_(target_list),
162 atom_cache_(atom_cache) {
165 bool 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;
173 return false;
176 bool TargetList::ContainsFormat(
177 const Clipboard::FormatType& format_type) const {
178 ::Atom atom = atom_cache_->GetAtom(format_type.ToString().c_str());
179 return ContainsAtom(atom);
182 bool TargetList::ContainsAtom(::Atom atom) const {
183 return find(target_list_.begin(), target_list_.end(), atom)
184 != target_list_.end();
187 } // namespace
189 ///////////////////////////////////////////////////////////////////////////////
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.
196 Clipboard::FormatType::FormatType() {
199 Clipboard::FormatType::FormatType(const std::string& native_format)
200 : data_(native_format) {
203 Clipboard::FormatType::~FormatType() {
206 std::string Clipboard::FormatType::Serialize() const {
207 return data_;
210 // static
211 Clipboard::FormatType Clipboard::FormatType::Deserialize(
212 const std::string& serialization) {
213 return FormatType(serialization);
216 bool Clipboard::FormatType::operator<(const FormatType& other) const {
217 return data_ < other.data_;
220 bool Clipboard::FormatType::Equals(const FormatType& other) const {
221 return data_ == other.data_;
224 ///////////////////////////////////////////////////////////////////////////////
225 // ClipboardAuraX11::AuraX11Details
227 // Private implementation of our X11 integration. Keeps X11 headers out of the
228 // majority of chrome, which break badly.
229 class ClipboardAuraX11::AuraX11Details : public PlatformEventDispatcher {
230 public:
231 AuraX11Details();
232 ~AuraX11Details() override;
234 X11AtomCache* atom_cache() { return &atom_cache_; }
236 // Returns the X11 type that we pass to various XSelection functions for the
237 // given type.
238 ::Atom LookupSelectionForClipboardType(ClipboardType type) const;
240 // Returns the X11 type that we pass to various XSelection functions for
241 // CLIPBOARD_TYPE_COPY_PASTE.
242 ::Atom GetCopyPasteSelection() const;
244 // Finds the SelectionFormatMap for the incoming selection atom.
245 const SelectionFormatMap& LookupStorageForAtom(::Atom atom);
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();
253 // Inserts a mapping into clipboard_data_.
254 void InsertMapping(const std::string& key,
255 const scoped_refptr<base::RefCountedMemory>& memory);
257 // Moves the temporary |clipboard_data_| to the long term data storage for
258 // |type|.
259 void TakeOwnershipOfSelection(ClipboardType type);
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.
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);
272 // Retrieves the list of possible data types the current clipboard owner has.
274 // If the selection holder is us, this is synchronous, otherwise this runs a
275 // blocking message loop.
276 TargetList WaitAndGetTargetsList(ClipboardType type);
278 // Returns a list of all text atoms that we handle.
279 std::vector< ::Atom> GetTextAtoms() const;
281 // Returns a vector with a |format| converted to an X11 atom.
282 std::vector< ::Atom> GetAtomsForFormat(const Clipboard::FormatType& format);
284 // Clears a certain clipboard type, whether we own it or not.
285 void Clear(ClipboardType type);
287 // If we own the CLIPBOARD selection, requests the clipboard manager to take
288 // ownership of it.
289 void StoreCopyPasteDataAndWait();
291 private:
292 // PlatformEventDispatcher:
293 bool CanDispatchEvent(const PlatformEvent& event) override;
294 uint32_t DispatchEvent(const PlatformEvent& event) override;
296 // Our X11 state.
297 Display* x_display_;
298 ::Window x_root_window_;
300 // Input-only window used as a selection owner.
301 ::Window x_window_;
303 X11AtomCache atom_cache_;
305 // Object which requests and receives selection data.
306 SelectionRequestor selection_requestor_;
308 // Temporary target map that we write to during DispatchObects.
309 SelectionFormatMap clipboard_data_;
311 // Objects which offer selection data to other windows.
312 SelectionOwner clipboard_owner_;
313 SelectionOwner primary_owner_;
315 DISALLOW_COPY_AND_ASSIGN(AuraX11Details);
318 ClipboardAuraX11::AuraX11Details::AuraX11Details()
319 : x_display_(gfx::GetXDisplay()),
320 x_root_window_(DefaultRootWindow(x_display_)),
321 x_window_(XCreateWindow(x_display_,
322 x_root_window_,
323 -100,
324 -100,
326 10, // x, y, width, height
327 0, // border width
328 CopyFromParent, // depth
329 InputOnly,
330 CopyFromParent, // visual
332 NULL)),
333 atom_cache_(x_display_, kAtomsToCache),
334 selection_requestor_(x_display_, x_window_, this),
335 clipboard_owner_(x_display_, x_window_, atom_cache_.GetAtom(kClipboard)),
336 primary_owner_(x_display_, x_window_, XA_PRIMARY) {
337 // We don't know all possible MIME types at compile time.
338 atom_cache_.allow_uncached_atoms();
340 XStoreName(x_display_, x_window_, "Chromium clipboard");
341 XSelectInput(x_display_, x_window_, PropertyChangeMask);
343 if (PlatformEventSource::GetInstance())
344 PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this);
347 ClipboardAuraX11::AuraX11Details::~AuraX11Details() {
348 if (PlatformEventSource::GetInstance())
349 PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this);
351 XDestroyWindow(x_display_, x_window_);
354 ::Atom ClipboardAuraX11::AuraX11Details::LookupSelectionForClipboardType(
355 ClipboardType type) const {
356 if (type == CLIPBOARD_TYPE_COPY_PASTE)
357 return GetCopyPasteSelection();
359 return XA_PRIMARY;
362 ::Atom ClipboardAuraX11::AuraX11Details::GetCopyPasteSelection() const {
363 return atom_cache_.GetAtom(kClipboard);
366 const SelectionFormatMap&
367 ClipboardAuraX11::AuraX11Details::LookupStorageForAtom(::Atom atom) {
368 if (atom == XA_PRIMARY)
369 return primary_owner_.selection_format_map();
371 DCHECK_EQ(GetCopyPasteSelection(), atom);
372 return clipboard_owner_.selection_format_map();
375 void ClipboardAuraX11::AuraX11Details::CreateNewClipboardData() {
376 clipboard_data_ = SelectionFormatMap();
379 void ClipboardAuraX11::AuraX11Details::InsertMapping(
380 const std::string& key,
381 const scoped_refptr<base::RefCountedMemory>& memory) {
382 ::Atom atom_key = atom_cache_.GetAtom(key.c_str());
383 clipboard_data_.Insert(atom_key, memory);
386 void ClipboardAuraX11::AuraX11Details::TakeOwnershipOfSelection(
387 ClipboardType type) {
388 if (type == CLIPBOARD_TYPE_COPY_PASTE)
389 return clipboard_owner_.TakeOwnershipOfSelection(clipboard_data_);
390 else
391 return primary_owner_.TakeOwnershipOfSelection(clipboard_data_);
394 SelectionData ClipboardAuraX11::AuraX11Details::RequestAndWaitForTypes(
395 ClipboardType type,
396 const std::vector<::Atom>& types) {
397 ::Atom selection_name = LookupSelectionForClipboardType(type);
398 if (XGetSelectionOwner(x_display_, selection_name) == x_window_) {
399 // We can local fastpath instead of playing the nested message loop game
400 // with the X server.
401 const SelectionFormatMap& format_map = LookupStorageForAtom(selection_name);
403 for (std::vector< ::Atom>::const_iterator it = types.begin();
404 it != types.end(); ++it) {
405 SelectionFormatMap::const_iterator format_map_it = format_map.find(*it);
406 if (format_map_it != format_map.end())
407 return SelectionData(format_map_it->first, format_map_it->second);
409 } else {
410 TargetList targets = WaitAndGetTargetsList(type);
412 ::Atom selection_name = LookupSelectionForClipboardType(type);
413 std::vector< ::Atom> intersection;
414 ui::GetAtomIntersection(types, targets.target_list(), &intersection);
415 return selection_requestor_.RequestAndWaitForTypes(selection_name,
416 intersection);
419 return SelectionData();
422 TargetList ClipboardAuraX11::AuraX11Details::WaitAndGetTargetsList(
423 ClipboardType type) {
424 ::Atom selection_name = LookupSelectionForClipboardType(type);
425 std::vector< ::Atom> out;
426 if (XGetSelectionOwner(x_display_, selection_name) == x_window_) {
427 // We can local fastpath and return the list of local targets.
428 const SelectionFormatMap& format_map = LookupStorageForAtom(selection_name);
430 for (SelectionFormatMap::const_iterator it = format_map.begin();
431 it != format_map.end(); ++it) {
432 out.push_back(it->first);
434 } else {
435 scoped_refptr<base::RefCountedMemory> data;
436 size_t out_data_items = 0;
437 ::Atom out_type = None;
439 if (selection_requestor_.PerformBlockingConvertSelection(
440 selection_name,
441 atom_cache_.GetAtom(kTargets),
442 &data,
443 &out_data_items,
444 &out_type)) {
445 // Some apps return an |out_type| of "TARGETS". (crbug.com/377893)
446 if (out_type == XA_ATOM || out_type == atom_cache_.GetAtom(kTargets)) {
447 const ::Atom* atom_array =
448 reinterpret_cast<const ::Atom*>(data->front());
449 for (size_t i = 0; i < out_data_items; ++i)
450 out.push_back(atom_array[i]);
452 } else {
453 // There was no target list. Most Java apps doesn't offer a TARGETS list,
454 // even though they AWT to. They will offer individual text types if you
455 // ask. If this is the case we attempt to make sense of the contents as
456 // text. This is pretty unfortunate since it means we have to actually
457 // copy the data to see if it is available, but at least this path
458 // shouldn't be hit for conforming programs.
459 std::vector< ::Atom> types = GetTextAtoms();
460 for (std::vector< ::Atom>::const_iterator it = types.begin();
461 it != types.end(); ++it) {
462 ::Atom type = None;
463 if (selection_requestor_.PerformBlockingConvertSelection(selection_name,
464 *it,
465 NULL,
466 NULL,
467 &type) &&
468 type == *it) {
469 out.push_back(*it);
475 return TargetList(out, &atom_cache_);
478 std::vector<::Atom> ClipboardAuraX11::AuraX11Details::GetTextAtoms() const {
479 return GetTextAtomsFrom(&atom_cache_);
482 std::vector<::Atom> ClipboardAuraX11::AuraX11Details::GetAtomsForFormat(
483 const Clipboard::FormatType& format) {
484 std::vector< ::Atom> atoms;
485 atoms.push_back(atom_cache_.GetAtom(format.ToString().c_str()));
486 return atoms;
489 void ClipboardAuraX11::AuraX11Details::Clear(ClipboardType type) {
490 if (type == CLIPBOARD_TYPE_COPY_PASTE)
491 clipboard_owner_.ClearSelectionOwner();
492 else
493 primary_owner_.ClearSelectionOwner();
496 void ClipboardAuraX11::AuraX11Details::StoreCopyPasteDataAndWait() {
497 ::Atom selection = GetCopyPasteSelection();
498 if (XGetSelectionOwner(x_display_, selection) != x_window_)
499 return;
501 ::Atom clipboard_manager_atom = atom_cache_.GetAtom(kClipboardManager);
502 if (XGetSelectionOwner(x_display_, clipboard_manager_atom) == None)
503 return;
505 const SelectionFormatMap& format_map = LookupStorageForAtom(selection);
506 if (format_map.size() == 0)
507 return;
508 std::vector<Atom> targets = format_map.GetTypes();
510 base::TimeTicks start = base::TimeTicks::Now();
511 selection_requestor_.PerformBlockingConvertSelectionWithParameter(
512 atom_cache_.GetAtom(kClipboardManager),
513 atom_cache_.GetAtom(kSaveTargets),
514 targets);
515 UMA_HISTOGRAM_TIMES("Clipboard.X11StoreCopyPasteDuration",
516 base::TimeTicks::Now() - start);
519 bool ClipboardAuraX11::AuraX11Details::CanDispatchEvent(
520 const PlatformEvent& event) {
521 if (event->xany.window == x_window_)
522 return true;
524 if (event->type == PropertyNotify) {
525 return primary_owner_.CanDispatchPropertyEvent(*event) ||
526 clipboard_owner_.CanDispatchPropertyEvent(*event) ||
527 selection_requestor_.CanDispatchPropertyEvent(*event);
529 return false;
532 uint32_t ClipboardAuraX11::AuraX11Details::DispatchEvent(
533 const PlatformEvent& xev) {
534 switch (xev->type) {
535 case SelectionRequest: {
536 if (xev->xselectionrequest.selection == XA_PRIMARY) {
537 primary_owner_.OnSelectionRequest(*xev);
538 } else {
539 // We should not get requests for the CLIPBOARD_MANAGER selection
540 // because we never take ownership of it.
541 DCHECK_EQ(GetCopyPasteSelection(), xev->xselectionrequest.selection);
542 clipboard_owner_.OnSelectionRequest(*xev);
544 break;
546 case SelectionNotify: {
547 selection_requestor_.OnSelectionNotify(*xev);
548 break;
550 case SelectionClear: {
551 if (xev->xselectionclear.selection == XA_PRIMARY) {
552 primary_owner_.OnSelectionClear(*xev);
553 } else {
554 // We should not get requests for the CLIPBOARD_MANAGER selection
555 // because we never take ownership of it.
556 DCHECK_EQ(GetCopyPasteSelection(), xev->xselection.selection);
557 clipboard_owner_.OnSelectionClear(*xev);
559 break;
561 case PropertyNotify: {
562 if (primary_owner_.CanDispatchPropertyEvent(*xev))
563 primary_owner_.OnPropertyEvent(*xev);
564 if (clipboard_owner_.CanDispatchPropertyEvent(*xev))
565 clipboard_owner_.OnPropertyEvent(*xev);
566 if (selection_requestor_.CanDispatchPropertyEvent(*xev))
567 selection_requestor_.OnPropertyEvent(*xev);
568 break;
570 default:
571 break;
574 return POST_DISPATCH_NONE;
577 ///////////////////////////////////////////////////////////////////////////////
578 // Various predefined FormatTypes.
579 // static
580 Clipboard::FormatType Clipboard::GetFormatType(
581 const std::string& format_string) {
582 return FormatType::Deserialize(format_string);
585 // static
586 const Clipboard::FormatType& Clipboard::GetUrlFormatType() {
587 CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeURIList));
588 return type;
591 // static
592 const Clipboard::FormatType& Clipboard::GetUrlWFormatType() {
593 return GetUrlFormatType();
596 // static
597 const Clipboard::FormatType& Clipboard::GetPlainTextFormatType() {
598 CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeText));
599 return type;
602 // static
603 const Clipboard::FormatType& Clipboard::GetPlainTextWFormatType() {
604 return GetPlainTextFormatType();
607 // static
608 const Clipboard::FormatType& Clipboard::GetFilenameFormatType() {
609 CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeFilename));
610 return type;
613 // static
614 const Clipboard::FormatType& Clipboard::GetFilenameWFormatType() {
615 return Clipboard::GetFilenameFormatType();
618 // static
619 const Clipboard::FormatType& Clipboard::GetHtmlFormatType() {
620 CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeHTML));
621 return type;
624 // static
625 const Clipboard::FormatType& Clipboard::GetRtfFormatType() {
626 CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeRTF));
627 return type;
630 // static
631 const Clipboard::FormatType& Clipboard::GetBitmapFormatType() {
632 CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypePNG));
633 return type;
636 // static
637 const Clipboard::FormatType& Clipboard::GetWebKitSmartPasteFormatType() {
638 CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeWebkitSmartPaste));
639 return type;
642 // static
643 const Clipboard::FormatType& Clipboard::GetWebCustomDataFormatType() {
644 CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeWebCustomData));
645 return type;
648 // static
649 const Clipboard::FormatType& Clipboard::GetPepperCustomDataFormatType() {
650 CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypePepperCustomData));
651 return type;
654 ///////////////////////////////////////////////////////////////////////////////
655 // Clipboard factory method.
656 Clipboard* Clipboard::Create() {
657 return new ClipboardAuraX11;
660 ///////////////////////////////////////////////////////////////////////////////
661 // ClipboardAuraX11
663 ClipboardAuraX11::ClipboardAuraX11() : aurax11_details_(new AuraX11Details) {
664 DCHECK(CalledOnValidThread());
667 ClipboardAuraX11::~ClipboardAuraX11() {
668 DCHECK(CalledOnValidThread());
670 aurax11_details_->StoreCopyPasteDataAndWait();
673 uint64 ClipboardAuraX11::GetSequenceNumber(ClipboardType type) const {
674 DCHECK(CalledOnValidThread());
675 if (type == CLIPBOARD_TYPE_COPY_PASTE)
676 return SelectionChangeObserver::GetInstance()->clipboard_sequence_number();
677 else
678 return SelectionChangeObserver::GetInstance()->primary_sequence_number();
681 bool ClipboardAuraX11::IsFormatAvailable(const FormatType& format,
682 ClipboardType type) const {
683 DCHECK(CalledOnValidThread());
684 DCHECK(IsSupportedClipboardType(type));
686 TargetList target_list = aurax11_details_->WaitAndGetTargetsList(type);
687 if (format.Equals(GetPlainTextFormatType()) ||
688 format.Equals(GetUrlFormatType())) {
689 return target_list.ContainsText();
691 return target_list.ContainsFormat(format);
694 void ClipboardAuraX11::Clear(ClipboardType type) {
695 DCHECK(CalledOnValidThread());
696 DCHECK(IsSupportedClipboardType(type));
697 aurax11_details_->Clear(type);
700 void ClipboardAuraX11::ReadAvailableTypes(ClipboardType type,
701 std::vector<base::string16>* types,
702 bool* contains_filenames) const {
703 DCHECK(CalledOnValidThread());
704 if (!types || !contains_filenames) {
705 NOTREACHED();
706 return;
709 TargetList target_list = aurax11_details_->WaitAndGetTargetsList(type);
711 types->clear();
713 if (target_list.ContainsText())
714 types->push_back(base::UTF8ToUTF16(kMimeTypeText));
715 if (target_list.ContainsFormat(GetHtmlFormatType()))
716 types->push_back(base::UTF8ToUTF16(kMimeTypeHTML));
717 if (target_list.ContainsFormat(GetRtfFormatType()))
718 types->push_back(base::UTF8ToUTF16(kMimeTypeRTF));
719 if (target_list.ContainsFormat(GetBitmapFormatType()))
720 types->push_back(base::UTF8ToUTF16(kMimeTypePNG));
721 *contains_filenames = false;
723 SelectionData data(aurax11_details_->RequestAndWaitForTypes(
724 type, aurax11_details_->GetAtomsForFormat(GetWebCustomDataFormatType())));
725 if (data.IsValid())
726 ReadCustomDataTypes(data.GetData(), data.GetSize(), types);
729 void ClipboardAuraX11::ReadText(ClipboardType type,
730 base::string16* result) const {
731 DCHECK(CalledOnValidThread());
733 SelectionData data(aurax11_details_->RequestAndWaitForTypes(
734 type, aurax11_details_->GetTextAtoms()));
735 if (data.IsValid()) {
736 std::string text = data.GetText();
737 *result = base::UTF8ToUTF16(text);
741 void ClipboardAuraX11::ReadAsciiText(ClipboardType type,
742 std::string* result) const {
743 DCHECK(CalledOnValidThread());
745 SelectionData data(aurax11_details_->RequestAndWaitForTypes(
746 type, aurax11_details_->GetTextAtoms()));
747 if (data.IsValid())
748 result->assign(data.GetText());
751 // TODO(estade): handle different charsets.
752 // TODO(port): set *src_url.
753 void ClipboardAuraX11::ReadHTML(ClipboardType type,
754 base::string16* markup,
755 std::string* src_url,
756 uint32* fragment_start,
757 uint32* fragment_end) const {
758 DCHECK(CalledOnValidThread());
759 markup->clear();
760 if (src_url)
761 src_url->clear();
762 *fragment_start = 0;
763 *fragment_end = 0;
765 SelectionData data(aurax11_details_->RequestAndWaitForTypes(
766 type, aurax11_details_->GetAtomsForFormat(GetHtmlFormatType())));
767 if (data.IsValid()) {
768 *markup = data.GetHtml();
770 *fragment_start = 0;
771 DCHECK(markup->length() <= kuint32max);
772 *fragment_end = static_cast<uint32>(markup->length());
776 void ClipboardAuraX11::ReadRTF(ClipboardType type, std::string* result) const {
777 DCHECK(CalledOnValidThread());
779 SelectionData data(aurax11_details_->RequestAndWaitForTypes(
780 type, aurax11_details_->GetAtomsForFormat(GetRtfFormatType())));
781 if (data.IsValid())
782 data.AssignTo(result);
785 SkBitmap ClipboardAuraX11::ReadImage(ClipboardType type) const {
786 DCHECK(CalledOnValidThread());
788 SelectionData data(aurax11_details_->RequestAndWaitForTypes(
789 type, aurax11_details_->GetAtomsForFormat(GetBitmapFormatType())));
790 if (data.IsValid()) {
791 SkBitmap bitmap;
792 if (gfx::PNGCodec::Decode(data.GetData(), data.GetSize(), &bitmap))
793 return SkBitmap(bitmap);
796 return SkBitmap();
799 void ClipboardAuraX11::ReadCustomData(ClipboardType clipboard_type,
800 const base::string16& type,
801 base::string16* result) const {
802 DCHECK(CalledOnValidThread());
804 SelectionData data(aurax11_details_->RequestAndWaitForTypes(
805 clipboard_type,
806 aurax11_details_->GetAtomsForFormat(GetWebCustomDataFormatType())));
807 if (data.IsValid())
808 ReadCustomDataForType(data.GetData(), data.GetSize(), type, result);
811 void ClipboardAuraX11::ReadBookmark(base::string16* title,
812 std::string* url) const {
813 DCHECK(CalledOnValidThread());
814 // TODO(erg): This was left NOTIMPLEMENTED() in the gtk port too.
815 NOTIMPLEMENTED();
818 void ClipboardAuraX11::ReadData(const FormatType& format,
819 std::string* result) const {
820 DCHECK(CalledOnValidThread());
822 SelectionData data(aurax11_details_->RequestAndWaitForTypes(
823 CLIPBOARD_TYPE_COPY_PASTE, aurax11_details_->GetAtomsForFormat(format)));
824 if (data.IsValid())
825 data.AssignTo(result);
828 void ClipboardAuraX11::WriteObjects(ClipboardType type,
829 const ObjectMap& objects) {
830 DCHECK(CalledOnValidThread());
831 DCHECK(IsSupportedClipboardType(type));
833 aurax11_details_->CreateNewClipboardData();
834 for (ObjectMap::const_iterator iter = objects.begin(); iter != objects.end();
835 ++iter) {
836 DispatchObject(static_cast<ObjectType>(iter->first), iter->second);
838 aurax11_details_->TakeOwnershipOfSelection(type);
840 if (type == CLIPBOARD_TYPE_COPY_PASTE) {
841 ObjectMap::const_iterator text_iter = objects.find(CBF_TEXT);
842 if (text_iter != objects.end()) {
843 aurax11_details_->CreateNewClipboardData();
844 const ObjectMapParams& params_vector = text_iter->second;
845 if (params_vector.size()) {
846 const ObjectMapParam& char_vector = params_vector[0];
847 if (char_vector.size())
848 WriteText(&char_vector.front(), char_vector.size());
850 aurax11_details_->TakeOwnershipOfSelection(CLIPBOARD_TYPE_SELECTION);
855 void ClipboardAuraX11::WriteText(const char* text_data, size_t text_len) {
856 std::string str(text_data, text_len);
857 scoped_refptr<base::RefCountedMemory> mem(
858 base::RefCountedString::TakeString(&str));
860 aurax11_details_->InsertMapping(kMimeTypeText, mem);
861 aurax11_details_->InsertMapping(kText, mem);
862 aurax11_details_->InsertMapping(kString, mem);
863 aurax11_details_->InsertMapping(kUtf8String, mem);
866 void ClipboardAuraX11::WriteHTML(const char* markup_data,
867 size_t markup_len,
868 const char* url_data,
869 size_t url_len) {
870 // TODO(estade): We need to expand relative links with |url_data|.
871 static const char* html_prefix = "<meta http-equiv=\"content-type\" "
872 "content=\"text/html; charset=utf-8\">";
873 std::string data = html_prefix;
874 data += std::string(markup_data, markup_len);
875 // Some programs expect NULL-terminated data. See http://crbug.com/42624
876 data += '\0';
878 scoped_refptr<base::RefCountedMemory> mem(
879 base::RefCountedString::TakeString(&data));
880 aurax11_details_->InsertMapping(kMimeTypeHTML, mem);
883 void ClipboardAuraX11::WriteRTF(const char* rtf_data, size_t data_len) {
884 WriteData(GetRtfFormatType(), rtf_data, data_len);
887 void ClipboardAuraX11::WriteBookmark(const char* title_data,
888 size_t title_len,
889 const char* url_data,
890 size_t url_len) {
891 // Write as a mozilla url (UTF16: URL, newline, title).
892 base::string16 url = base::UTF8ToUTF16(std::string(url_data, url_len) + "\n");
893 base::string16 title =
894 base::UTF8ToUTF16(base::StringPiece(title_data, title_len));
896 std::vector<unsigned char> data;
897 ui::AddString16ToVector(url, &data);
898 ui::AddString16ToVector(title, &data);
899 scoped_refptr<base::RefCountedMemory> mem(
900 base::RefCountedBytes::TakeVector(&data));
902 aurax11_details_->InsertMapping(kMimeTypeMozillaURL, mem);
905 // Write an extra flavor that signifies WebKit was the last to modify the
906 // pasteboard. This flavor has no data.
907 void ClipboardAuraX11::WriteWebSmartPaste() {
908 std::string empty;
909 aurax11_details_->InsertMapping(
910 kMimeTypeWebkitSmartPaste,
911 scoped_refptr<base::RefCountedMemory>(
912 base::RefCountedString::TakeString(&empty)));
915 void ClipboardAuraX11::WriteBitmap(const SkBitmap& bitmap) {
916 // Encode the bitmap as a PNG for transport.
917 std::vector<unsigned char> output;
918 if (gfx::PNGCodec::FastEncodeBGRASkBitmap(bitmap, false, &output)) {
919 aurax11_details_->InsertMapping(kMimeTypePNG,
920 base::RefCountedBytes::TakeVector(
921 &output));
925 void ClipboardAuraX11::WriteData(const FormatType& format,
926 const char* data_data,
927 size_t data_len) {
928 // We assume that certain mapping types are only written by trusted code.
929 // Therefore we must upkeep their integrity.
930 if (format.Equals(GetBitmapFormatType()))
931 return;
933 std::vector<unsigned char> bytes(data_data, data_data + data_len);
934 scoped_refptr<base::RefCountedMemory> mem(
935 base::RefCountedBytes::TakeVector(&bytes));
936 aurax11_details_->InsertMapping(format.ToString(), mem);
939 } // namespace ui