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>
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"
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
[] = {
49 Clipboard::kMimeTypePNG
,
52 kMimeTypeWebkitSmartPaste
,
61 ///////////////////////////////////////////////////////////////////////////////
63 // Uses the XFixes API to provide sequence numbers for GetSequenceNumber().
64 class SelectionChangeObserver
: public ui::PlatformEventObserver
{
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_
; }
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
{}
85 uint64 clipboard_sequence_number_
;
86 uint64 primary_sequence_number_
;
88 DISALLOW_COPY_AND_ASSIGN(SelectionChangeObserver
);
91 SelectionChangeObserver::SelectionChangeObserver()
93 clipboard_atom_(None
),
94 clipboard_sequence_number_(0),
95 primary_sequence_number_(0) {
97 if (XFixesQueryExtension(gfx::GetXDisplay(), &event_base_
, &ignored
)) {
98 clipboard_atom_
= XInternAtom(gfx::GetXDisplay(), kClipboard
, false);
99 XFixesSelectSelectionInput(gfx::GetXDisplay(), GetX11RootWindow(),
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(),
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_
++;
134 DLOG(ERROR
) << "Unexpected selection atom: " << ev
->selection
;
139 ///////////////////////////////////////////////////////////////////////////////
141 // Represents a list of possible return types. Copy constructable.
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;
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
))
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();
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 {
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
{
232 ~AuraX11Details() override
;
234 X11AtomCache
* atom_cache() { return &atom_cache_
; }
236 // Returns the X11 type that we pass to various XSelection functions for the
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
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
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
289 void StoreCopyPasteDataAndWait();
292 // PlatformEventDispatcher:
293 bool CanDispatchEvent(const PlatformEvent
& event
) override
;
294 uint32_t DispatchEvent(const PlatformEvent
& event
) override
;
298 ::Window x_root_window_
;
300 // Input-only window used as a selection owner.
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_
,
326 10, // x, y, width, height
328 CopyFromParent
, // depth
330 CopyFromParent
, // visual
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();
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_
);
391 return primary_owner_
.TakeOwnershipOfSelection(clipboard_data_
);
394 SelectionData
ClipboardAuraX11::AuraX11Details::RequestAndWaitForTypes(
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
);
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
,
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
);
435 scoped_refptr
<base::RefCountedMemory
> data
;
436 size_t out_data_items
= 0;
437 ::Atom out_type
= None
;
439 if (selection_requestor_
.PerformBlockingConvertSelection(
441 atom_cache_
.GetAtom(kTargets
),
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
]);
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
) {
463 if (selection_requestor_
.PerformBlockingConvertSelection(selection_name
,
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()));
489 void ClipboardAuraX11::AuraX11Details::Clear(ClipboardType type
) {
490 if (type
== CLIPBOARD_TYPE_COPY_PASTE
)
491 clipboard_owner_
.ClearSelectionOwner();
493 primary_owner_
.ClearSelectionOwner();
496 void ClipboardAuraX11::AuraX11Details::StoreCopyPasteDataAndWait() {
497 ::Atom selection
= GetCopyPasteSelection();
498 if (XGetSelectionOwner(x_display_
, selection
) != x_window_
)
501 ::Atom clipboard_manager_atom
= atom_cache_
.GetAtom(kClipboardManager
);
502 if (XGetSelectionOwner(x_display_
, clipboard_manager_atom
) == None
)
505 const SelectionFormatMap
& format_map
= LookupStorageForAtom(selection
);
506 if (format_map
.size() == 0)
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
),
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_
)
524 if (event
->type
== PropertyNotify
) {
525 return primary_owner_
.CanDispatchPropertyEvent(*event
) ||
526 clipboard_owner_
.CanDispatchPropertyEvent(*event
) ||
527 selection_requestor_
.CanDispatchPropertyEvent(*event
);
532 uint32_t ClipboardAuraX11::AuraX11Details::DispatchEvent(
533 const PlatformEvent
& xev
) {
535 case SelectionRequest
: {
536 if (xev
->xselectionrequest
.selection
== XA_PRIMARY
) {
537 primary_owner_
.OnSelectionRequest(*xev
);
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
);
546 case SelectionNotify
: {
547 selection_requestor_
.OnSelectionNotify(*xev
);
550 case SelectionClear
: {
551 if (xev
->xselectionclear
.selection
== XA_PRIMARY
) {
552 primary_owner_
.OnSelectionClear(*xev
);
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
);
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
);
574 return POST_DISPATCH_NONE
;
577 ///////////////////////////////////////////////////////////////////////////////
578 // Various predefined FormatTypes.
580 Clipboard::FormatType
Clipboard::GetFormatType(
581 const std::string
& format_string
) {
582 return FormatType::Deserialize(format_string
);
586 const Clipboard::FormatType
& Clipboard::GetUrlFormatType() {
587 CR_DEFINE_STATIC_LOCAL(FormatType
, type
, (kMimeTypeURIList
));
592 const Clipboard::FormatType
& Clipboard::GetUrlWFormatType() {
593 return GetUrlFormatType();
597 const Clipboard::FormatType
& Clipboard::GetPlainTextFormatType() {
598 CR_DEFINE_STATIC_LOCAL(FormatType
, type
, (kMimeTypeText
));
603 const Clipboard::FormatType
& Clipboard::GetPlainTextWFormatType() {
604 return GetPlainTextFormatType();
608 const Clipboard::FormatType
& Clipboard::GetFilenameFormatType() {
609 CR_DEFINE_STATIC_LOCAL(FormatType
, type
, (kMimeTypeFilename
));
614 const Clipboard::FormatType
& Clipboard::GetFilenameWFormatType() {
615 return Clipboard::GetFilenameFormatType();
619 const Clipboard::FormatType
& Clipboard::GetHtmlFormatType() {
620 CR_DEFINE_STATIC_LOCAL(FormatType
, type
, (kMimeTypeHTML
));
625 const Clipboard::FormatType
& Clipboard::GetRtfFormatType() {
626 CR_DEFINE_STATIC_LOCAL(FormatType
, type
, (kMimeTypeRTF
));
631 const Clipboard::FormatType
& Clipboard::GetBitmapFormatType() {
632 CR_DEFINE_STATIC_LOCAL(FormatType
, type
, (kMimeTypePNG
));
637 const Clipboard::FormatType
& Clipboard::GetWebKitSmartPasteFormatType() {
638 CR_DEFINE_STATIC_LOCAL(FormatType
, type
, (kMimeTypeWebkitSmartPaste
));
643 const Clipboard::FormatType
& Clipboard::GetWebCustomDataFormatType() {
644 CR_DEFINE_STATIC_LOCAL(FormatType
, type
, (kMimeTypeWebCustomData
));
649 const Clipboard::FormatType
& Clipboard::GetPepperCustomDataFormatType() {
650 CR_DEFINE_STATIC_LOCAL(FormatType
, type
, (kMimeTypePepperCustomData
));
654 ///////////////////////////////////////////////////////////////////////////////
655 // Clipboard factory method.
656 Clipboard
* Clipboard::Create() {
657 return new ClipboardAuraX11
;
660 ///////////////////////////////////////////////////////////////////////////////
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();
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
) {
709 TargetList target_list
= aurax11_details_
->WaitAndGetTargetsList(type
);
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())));
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()));
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());
765 SelectionData
data(aurax11_details_
->RequestAndWaitForTypes(
766 type
, aurax11_details_
->GetAtomsForFormat(GetHtmlFormatType())));
767 if (data
.IsValid()) {
768 *markup
= data
.GetHtml();
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())));
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()) {
792 if (gfx::PNGCodec::Decode(data
.GetData(), data
.GetSize(), &bitmap
))
793 return SkBitmap(bitmap
);
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(
806 aurax11_details_
->GetAtomsForFormat(GetWebCustomDataFormatType())));
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.
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
)));
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();
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
,
868 const char* url_data
,
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
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
,
889 const char* url_data
,
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() {
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(
925 void ClipboardAuraX11::WriteData(const FormatType
& format
,
926 const char* data_data
,
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()))
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
);