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.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/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 virtual ~SelectionChangeObserver();
79 // ui::PlatformEventObserver:
80 virtual void WillProcessEvent(const ui::PlatformEvent
& event
) OVERRIDE
;
81 virtual 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 // Clipboard::AuraX11Details
227 // Private implementation of our X11 integration. Keeps X11 headers out of the
228 // majority of chrome, which break badly.
229 class Clipboard::AuraX11Details
: public PlatformEventDispatcher
{
232 virtual ~AuraX11Details();
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 virtual bool CanDispatchEvent(const PlatformEvent
& event
) OVERRIDE
;
294 virtual 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 Clipboard::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
325 CopyFromParent
, // depth
327 CopyFromParent
, // visual
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();
337 XStoreName(x_display_
, x_window_
, "Chromium clipboard");
338 XSelectInput(x_display_
, x_window_
, PropertyChangeMask
);
340 if (PlatformEventSource::GetInstance())
341 PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this);
344 Clipboard::AuraX11Details::~AuraX11Details() {
345 if (PlatformEventSource::GetInstance())
346 PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this);
348 XDestroyWindow(x_display_
, x_window_
);
351 ::Atom
Clipboard::AuraX11Details::LookupSelectionForClipboardType(
352 ClipboardType type
) const {
353 if (type
== CLIPBOARD_TYPE_COPY_PASTE
)
354 return GetCopyPasteSelection();
359 ::Atom
Clipboard::AuraX11Details::GetCopyPasteSelection() const {
360 return atom_cache_
.GetAtom(kClipboard
);
363 const SelectionFormatMap
& Clipboard::AuraX11Details::LookupStorageForAtom(
365 if (atom
== XA_PRIMARY
)
366 return primary_owner_
.selection_format_map();
368 DCHECK_EQ(GetCopyPasteSelection(), atom
);
369 return clipboard_owner_
.selection_format_map();
372 void Clipboard::AuraX11Details::CreateNewClipboardData() {
373 clipboard_data_
= SelectionFormatMap();
376 void 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
);
383 void Clipboard::AuraX11Details::TakeOwnershipOfSelection(ClipboardType type
) {
384 if (type
== CLIPBOARD_TYPE_COPY_PASTE
)
385 return clipboard_owner_
.TakeOwnershipOfSelection(clipboard_data_
);
387 return primary_owner_
.TakeOwnershipOfSelection(clipboard_data_
);
390 SelectionData
Clipboard::AuraX11Details::RequestAndWaitForTypes(
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
);
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
);
406 TargetList targets
= WaitAndGetTargetsList(type
);
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
,
415 return SelectionData();
418 TargetList
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
);
426 for (SelectionFormatMap::const_iterator it
= format_map
.begin();
427 it
!= format_map
.end(); ++it
) {
428 out
.push_back(it
->first
);
431 scoped_refptr
<base::RefCountedMemory
> data
;
432 size_t out_data_items
= 0;
433 ::Atom out_type
= None
;
435 if (selection_requestor_
.PerformBlockingConvertSelection(
437 atom_cache_
.GetAtom(kTargets
),
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
]);
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
) {
459 if (selection_requestor_
.PerformBlockingConvertSelection(selection_name
,
471 return TargetList(out
, &atom_cache_
);
474 std::vector
< ::Atom
> Clipboard::AuraX11Details::GetTextAtoms() const {
475 return GetTextAtomsFrom(&atom_cache_
);
478 std::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()));
485 void Clipboard::AuraX11Details::Clear(ClipboardType type
) {
486 if (type
== CLIPBOARD_TYPE_COPY_PASTE
)
487 clipboard_owner_
.ClearSelectionOwner();
489 primary_owner_
.ClearSelectionOwner();
492 void Clipboard::AuraX11Details::StoreCopyPasteDataAndWait() {
493 ::Atom selection
= GetCopyPasteSelection();
494 if (XGetSelectionOwner(x_display_
, selection
) != x_window_
)
497 ::Atom clipboard_manager_atom
= atom_cache_
.GetAtom(kClipboardManager
);
498 if (XGetSelectionOwner(x_display_
, clipboard_manager_atom
) == None
)
501 const SelectionFormatMap
& format_map
= LookupStorageForAtom(selection
);
502 if (format_map
.size() == 0)
504 std::vector
<Atom
> targets
= format_map
.GetTypes();
506 base::TimeTicks start
= base::TimeTicks::Now();
507 selection_requestor_
.PerformBlockingConvertSelectionWithParameter(
508 atom_cache_
.GetAtom(kClipboardManager
),
509 atom_cache_
.GetAtom(kSaveTargets
),
511 UMA_HISTOGRAM_TIMES("Clipboard.X11StoreCopyPasteDuration",
512 base::TimeTicks::Now() - start
);
515 bool Clipboard::AuraX11Details::CanDispatchEvent(const PlatformEvent
& event
) {
516 if (event
->xany
.window
== x_window_
)
519 if (event
->type
== PropertyNotify
) {
520 return primary_owner_
.CanDispatchPropertyEvent(*event
) ||
521 clipboard_owner_
.CanDispatchPropertyEvent(*event
) ||
522 selection_requestor_
.CanDispatchPropertyEvent(*event
);
527 uint32_t Clipboard::AuraX11Details::DispatchEvent(const PlatformEvent
& xev
) {
529 case SelectionRequest
: {
530 if (xev
->xselectionrequest
.selection
== XA_PRIMARY
) {
531 primary_owner_
.OnSelectionRequest(*xev
);
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
);
540 case SelectionNotify
: {
541 selection_requestor_
.OnSelectionNotify(*xev
);
544 case SelectionClear
: {
545 if (xev
->xselectionclear
.selection
== XA_PRIMARY
) {
546 primary_owner_
.OnSelectionClear(*xev
);
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
);
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
);
568 return POST_DISPATCH_NONE
;
571 ///////////////////////////////////////////////////////////////////////////////
574 Clipboard::Clipboard()
575 : aurax11_details_(new AuraX11Details
) {
576 DCHECK(CalledOnValidThread());
579 Clipboard::~Clipboard() {
580 DCHECK(CalledOnValidThread());
582 aurax11_details_
->StoreCopyPasteDataAndWait();
585 void Clipboard::WriteObjects(ClipboardType type
, const ObjectMap
& objects
) {
586 DCHECK(CalledOnValidThread());
587 DCHECK(IsSupportedClipboardType(type
));
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
);
594 aurax11_details_
->TakeOwnershipOfSelection(type
);
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());
606 aurax11_details_
->TakeOwnershipOfSelection(CLIPBOARD_TYPE_SELECTION
);
611 bool Clipboard::IsFormatAvailable(const FormatType
& format
,
612 ClipboardType type
) const {
613 DCHECK(CalledOnValidThread());
614 DCHECK(IsSupportedClipboardType(type
));
616 TargetList target_list
= aurax11_details_
->WaitAndGetTargetsList(type
);
617 if (format
.Equals(GetPlainTextFormatType()) ||
618 format
.Equals(GetUrlFormatType())) {
619 return target_list
.ContainsText();
621 return target_list
.ContainsFormat(format
);
624 void Clipboard::Clear(ClipboardType type
) {
625 DCHECK(CalledOnValidThread());
626 DCHECK(IsSupportedClipboardType(type
));
627 aurax11_details_
->Clear(type
);
630 void Clipboard::ReadAvailableTypes(ClipboardType type
,
631 std::vector
<base::string16
>* types
,
632 bool* contains_filenames
) const {
633 DCHECK(CalledOnValidThread());
634 if (!types
|| !contains_filenames
) {
639 TargetList target_list
= aurax11_details_
->WaitAndGetTargetsList(type
);
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;
653 SelectionData
data(aurax11_details_
->RequestAndWaitForTypes(
654 type
, aurax11_details_
->GetAtomsForFormat(GetWebCustomDataFormatType())));
656 ReadCustomDataTypes(data
.GetData(), data
.GetSize(), types
);
659 void Clipboard::ReadText(ClipboardType type
, base::string16
* result
) const {
660 DCHECK(CalledOnValidThread());
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
);
670 void Clipboard::ReadAsciiText(ClipboardType type
, std::string
* result
) const {
671 DCHECK(CalledOnValidThread());
673 SelectionData
data(aurax11_details_
->RequestAndWaitForTypes(
674 type
, aurax11_details_
->GetTextAtoms()));
676 result
->assign(data
.GetText());
679 // TODO(estade): handle different charsets.
680 // TODO(port): set *src_url.
681 void 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());
693 SelectionData
data(aurax11_details_
->RequestAndWaitForTypes(
694 type
, aurax11_details_
->GetAtomsForFormat(GetHtmlFormatType())));
695 if (data
.IsValid()) {
696 *markup
= data
.GetHtml();
699 DCHECK(markup
->length() <= kuint32max
);
700 *fragment_end
= static_cast<uint32
>(markup
->length());
704 void Clipboard::ReadRTF(ClipboardType type
, std::string
* result
) const {
705 DCHECK(CalledOnValidThread());
707 SelectionData
data(aurax11_details_
->RequestAndWaitForTypes(
708 type
, aurax11_details_
->GetAtomsForFormat(GetRtfFormatType())));
710 data
.AssignTo(result
);
713 SkBitmap
Clipboard::ReadImage(ClipboardType type
) const {
714 DCHECK(CalledOnValidThread());
716 SelectionData
data(aurax11_details_
->RequestAndWaitForTypes(
717 type
, aurax11_details_
->GetAtomsForFormat(GetBitmapFormatType())));
718 if (data
.IsValid()) {
720 if (gfx::PNGCodec::Decode(data
.GetData(), data
.GetSize(), &bitmap
))
721 return SkBitmap(bitmap
);
727 void Clipboard::ReadCustomData(ClipboardType clipboard_type
,
728 const base::string16
& type
,
729 base::string16
* result
) const {
730 DCHECK(CalledOnValidThread());
732 SelectionData
data(aurax11_details_
->RequestAndWaitForTypes(
734 aurax11_details_
->GetAtomsForFormat(GetWebCustomDataFormatType())));
736 ReadCustomDataForType(data
.GetData(), data
.GetSize(), type
, result
);
739 void Clipboard::ReadBookmark(base::string16
* title
, std::string
* url
) const {
740 DCHECK(CalledOnValidThread());
741 // TODO(erg): This was left NOTIMPLEMENTED() in the gtk port too.
745 void Clipboard::ReadData(const FormatType
& format
, std::string
* result
) const {
746 DCHECK(CalledOnValidThread());
748 SelectionData
data(aurax11_details_
->RequestAndWaitForTypes(
749 CLIPBOARD_TYPE_COPY_PASTE
, aurax11_details_
->GetAtomsForFormat(format
)));
751 data
.AssignTo(result
);
754 uint64
Clipboard::GetSequenceNumber(ClipboardType type
) {
755 DCHECK(CalledOnValidThread());
756 if (type
== CLIPBOARD_TYPE_COPY_PASTE
)
757 return SelectionChangeObserver::GetInstance()->clipboard_sequence_number();
759 return SelectionChangeObserver::GetInstance()->primary_sequence_number();
762 void 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
));
767 aurax11_details_
->InsertMapping(kMimeTypeText
, mem
);
768 aurax11_details_
->InsertMapping(kText
, mem
);
769 aurax11_details_
->InsertMapping(kString
, mem
);
770 aurax11_details_
->InsertMapping(kUtf8String
, mem
);
773 void Clipboard::WriteHTML(const char* markup_data
,
775 const char* url_data
,
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
785 scoped_refptr
<base::RefCountedMemory
> mem(
786 base::RefCountedString::TakeString(&data
));
787 aurax11_details_
->InsertMapping(kMimeTypeHTML
, mem
);
790 void Clipboard::WriteRTF(const char* rtf_data
, size_t data_len
) {
791 WriteData(GetRtfFormatType(), rtf_data
, data_len
);
794 void Clipboard::WriteBookmark(const char* title_data
,
796 const char* url_data
,
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
));
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
));
808 aurax11_details_
->InsertMapping(kMimeTypeMozillaURL
, mem
);
811 // Write an extra flavor that signifies WebKit was the last to modify the
812 // pasteboard. This flavor has no data.
813 void Clipboard::WriteWebSmartPaste() {
815 aurax11_details_
->InsertMapping(
816 kMimeTypeWebkitSmartPaste
,
817 scoped_refptr
<base::RefCountedMemory
>(
818 base::RefCountedString::TakeString(&empty
)));
821 void 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(
831 void Clipboard::WriteData(const FormatType
& format
,
832 const char* data_data
,
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()))
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
);
846 Clipboard::FormatType
Clipboard::GetFormatType(
847 const std::string
& format_string
) {
848 return FormatType::Deserialize(format_string
);
852 const Clipboard::FormatType
& Clipboard::GetUrlFormatType() {
853 CR_DEFINE_STATIC_LOCAL(FormatType
, type
, (kMimeTypeURIList
));
858 const Clipboard::FormatType
& Clipboard::GetUrlWFormatType() {
859 return GetUrlFormatType();
863 const Clipboard::FormatType
& Clipboard::GetPlainTextFormatType() {
864 CR_DEFINE_STATIC_LOCAL(FormatType
, type
, (kMimeTypeText
));
869 const Clipboard::FormatType
& Clipboard::GetPlainTextWFormatType() {
870 return GetPlainTextFormatType();
874 const Clipboard::FormatType
& Clipboard::GetFilenameFormatType() {
875 CR_DEFINE_STATIC_LOCAL(FormatType
, type
, (kMimeTypeFilename
));
880 const Clipboard::FormatType
& Clipboard::GetFilenameWFormatType() {
881 return Clipboard::GetFilenameFormatType();
885 const Clipboard::FormatType
& Clipboard::GetHtmlFormatType() {
886 CR_DEFINE_STATIC_LOCAL(FormatType
, type
, (kMimeTypeHTML
));
891 const Clipboard::FormatType
& Clipboard::GetRtfFormatType() {
892 CR_DEFINE_STATIC_LOCAL(FormatType
, type
, (kMimeTypeRTF
));
897 const Clipboard::FormatType
& Clipboard::GetBitmapFormatType() {
898 CR_DEFINE_STATIC_LOCAL(FormatType
, type
, (kMimeTypePNG
));
903 const Clipboard::FormatType
& Clipboard::GetWebKitSmartPasteFormatType() {
904 CR_DEFINE_STATIC_LOCAL(FormatType
, type
, (kMimeTypeWebkitSmartPaste
));
909 const Clipboard::FormatType
& Clipboard::GetWebCustomDataFormatType() {
910 CR_DEFINE_STATIC_LOCAL(FormatType
, type
, (kMimeTypeWebCustomData
));
915 const Clipboard::FormatType
& Clipboard::GetPepperCustomDataFormatType() {
916 CR_DEFINE_STATIC_LOCAL(FormatType
, type
, (kMimeTypePepperCustomData
));