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 // Returns the object which is responsible for communication on |type|.
245 SelectionRequestor
* GetSelectionRequestorForClipboardType(ClipboardType type
);
247 // Finds the SelectionFormatMap for the incoming selection atom.
248 const SelectionFormatMap
& LookupStorageForAtom(::Atom atom
);
250 // As we need to collect all the data types before we tell X11 that we own a
251 // particular selection, we create a temporary clipboard mapping that
252 // InsertMapping writes to. Then we commit it in TakeOwnershipOfSelection,
253 // where we save it in one of the clipboard data slots.
254 void CreateNewClipboardData();
256 // Inserts a mapping into clipboard_data_.
257 void InsertMapping(const std::string
& key
,
258 const scoped_refptr
<base::RefCountedMemory
>& memory
);
260 // Moves the temporary |clipboard_data_| to the long term data storage for
262 void TakeOwnershipOfSelection(ClipboardType type
);
264 // Returns the first of |types| offered by the current selection holder in
265 // |data_out|, or returns NULL if none of those types are available.
267 // If the selection holder is us, this call is synchronous and we pull
268 // the data out of |clipboard_selection_| or |primary_selection_|. If the
269 // selection holder is some other window, we spin up a nested message loop
270 // and do the asynchronous dance with whatever application is holding the
272 ui::SelectionData
RequestAndWaitForTypes(ClipboardType type
,
273 const std::vector
< ::Atom
>& types
);
275 // Retrieves the list of possible data types the current clipboard owner has.
277 // If the selection holder is us, this is synchronous, otherwise this runs a
278 // blocking message loop.
279 TargetList
WaitAndGetTargetsList(ClipboardType type
);
281 // Returns a list of all text atoms that we handle.
282 std::vector
< ::Atom
> GetTextAtoms() const;
284 // Returns a vector with a |format| converted to an X11 atom.
285 std::vector
< ::Atom
> GetAtomsForFormat(const Clipboard::FormatType
& format
);
287 // Clears a certain clipboard type, whether we own it or not.
288 void Clear(ClipboardType type
);
290 // If we own the CLIPBOARD selection, requests the clipboard manager to take
292 void StoreCopyPasteDataAndWait();
295 // PlatformEventDispatcher:
296 virtual bool CanDispatchEvent(const PlatformEvent
& event
) OVERRIDE
;
297 virtual uint32_t DispatchEvent(const PlatformEvent
& event
) OVERRIDE
;
301 ::Window x_root_window_
;
303 // Input-only window used as a selection owner.
306 X11AtomCache atom_cache_
;
308 // Objects which request and receive selection data.
309 SelectionRequestor clipboard_requestor_
;
310 SelectionRequestor primary_requestor_
;
311 SelectionRequestor clipboard_manager_requestor_
;
313 // Temporary target map that we write to during DispatchObects.
314 SelectionFormatMap clipboard_data_
;
316 // Objects which offer selection data to other windows.
317 SelectionOwner clipboard_owner_
;
318 SelectionOwner primary_owner_
;
320 DISALLOW_COPY_AND_ASSIGN(AuraX11Details
);
323 Clipboard::AuraX11Details::AuraX11Details()
324 : x_display_(gfx::GetXDisplay()),
325 x_root_window_(DefaultRootWindow(x_display_
)),
326 x_window_(XCreateWindow(
327 x_display_
, x_root_window_
,
328 -100, -100, 10, 10, // x, y, width, height
330 CopyFromParent
, // depth
332 CopyFromParent
, // visual
335 atom_cache_(x_display_
, kAtomsToCache
),
336 clipboard_requestor_(x_display_
, x_window_
,
337 atom_cache_
.GetAtom(kClipboard
), this),
338 primary_requestor_(x_display_
, x_window_
, XA_PRIMARY
, this),
339 clipboard_manager_requestor_(x_display_
, x_window_
,
340 atom_cache_
.GetAtom(kClipboardManager
),
342 clipboard_owner_(x_display_
, x_window_
, atom_cache_
.GetAtom(kClipboard
)),
343 primary_owner_(x_display_
, x_window_
, XA_PRIMARY
) {
344 // We don't know all possible MIME types at compile time.
345 atom_cache_
.allow_uncached_atoms();
347 XStoreName(x_display_
, x_window_
, "Chromium clipboard");
348 XSelectInput(x_display_
, x_window_
, PropertyChangeMask
);
350 if (PlatformEventSource::GetInstance())
351 PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this);
354 Clipboard::AuraX11Details::~AuraX11Details() {
355 if (PlatformEventSource::GetInstance())
356 PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this);
358 XDestroyWindow(x_display_
, x_window_
);
361 ::Atom
Clipboard::AuraX11Details::LookupSelectionForClipboardType(
362 ClipboardType type
) const {
363 if (type
== CLIPBOARD_TYPE_COPY_PASTE
)
364 return GetCopyPasteSelection();
369 ::Atom
Clipboard::AuraX11Details::GetCopyPasteSelection() const {
370 return atom_cache_
.GetAtom(kClipboard
);
373 const SelectionFormatMap
& Clipboard::AuraX11Details::LookupStorageForAtom(
375 if (atom
== XA_PRIMARY
)
376 return primary_owner_
.selection_format_map();
378 DCHECK_EQ(GetCopyPasteSelection(), atom
);
379 return clipboard_owner_
.selection_format_map();
382 ui::SelectionRequestor
*
383 Clipboard::AuraX11Details::GetSelectionRequestorForClipboardType(
384 ClipboardType type
) {
385 if (type
== CLIPBOARD_TYPE_COPY_PASTE
)
386 return &clipboard_requestor_
;
388 return &primary_requestor_
;
391 void Clipboard::AuraX11Details::CreateNewClipboardData() {
392 clipboard_data_
= SelectionFormatMap();
395 void Clipboard::AuraX11Details::InsertMapping(
396 const std::string
& key
,
397 const scoped_refptr
<base::RefCountedMemory
>& memory
) {
398 ::Atom atom_key
= atom_cache_
.GetAtom(key
.c_str());
399 clipboard_data_
.Insert(atom_key
, memory
);
402 void Clipboard::AuraX11Details::TakeOwnershipOfSelection(ClipboardType type
) {
403 if (type
== CLIPBOARD_TYPE_COPY_PASTE
)
404 return clipboard_owner_
.TakeOwnershipOfSelection(clipboard_data_
);
406 return primary_owner_
.TakeOwnershipOfSelection(clipboard_data_
);
409 SelectionData
Clipboard::AuraX11Details::RequestAndWaitForTypes(
411 const std::vector
< ::Atom
>& types
) {
412 ::Atom selection_name
= LookupSelectionForClipboardType(type
);
413 if (XGetSelectionOwner(x_display_
, selection_name
) == x_window_
) {
414 // We can local fastpath instead of playing the nested message loop game
415 // with the X server.
416 const SelectionFormatMap
& format_map
= LookupStorageForAtom(selection_name
);
418 for (std::vector
< ::Atom
>::const_iterator it
= types
.begin();
419 it
!= types
.end(); ++it
) {
420 SelectionFormatMap::const_iterator format_map_it
= format_map
.find(*it
);
421 if (format_map_it
!= format_map
.end())
422 return SelectionData(format_map_it
->first
, format_map_it
->second
);
425 TargetList targets
= WaitAndGetTargetsList(type
);
426 SelectionRequestor
* receiver
= GetSelectionRequestorForClipboardType(type
);
428 std::vector
< ::Atom
> intersection
;
429 ui::GetAtomIntersection(types
, targets
.target_list(), &intersection
);
430 return receiver
->RequestAndWaitForTypes(intersection
);
433 return SelectionData();
436 TargetList
Clipboard::AuraX11Details::WaitAndGetTargetsList(
437 ClipboardType type
) {
438 ::Atom selection_name
= LookupSelectionForClipboardType(type
);
439 std::vector
< ::Atom
> out
;
440 if (XGetSelectionOwner(x_display_
, selection_name
) == x_window_
) {
441 // We can local fastpath and return the list of local targets.
442 const SelectionFormatMap
& format_map
= LookupStorageForAtom(selection_name
);
444 for (SelectionFormatMap::const_iterator it
= format_map
.begin();
445 it
!= format_map
.end(); ++it
) {
446 out
.push_back(it
->first
);
449 scoped_refptr
<base::RefCountedMemory
> data
;
450 size_t out_data_items
= 0;
451 ::Atom out_type
= None
;
453 SelectionRequestor
* receiver
= GetSelectionRequestorForClipboardType(type
);
454 if (receiver
->PerformBlockingConvertSelection(atom_cache_
.GetAtom(kTargets
),
458 // Some apps return an |out_type| of "TARGETS". (crbug.com/377893)
459 if (out_type
== XA_ATOM
|| out_type
== atom_cache_
.GetAtom(kTargets
)) {
460 const ::Atom
* atom_array
=
461 reinterpret_cast<const ::Atom
*>(data
->front());
462 for (size_t i
= 0; i
< out_data_items
; ++i
)
463 out
.push_back(atom_array
[i
]);
466 // There was no target list. Most Java apps doesn't offer a TARGETS list,
467 // even though they AWT to. They will offer individual text types if you
468 // ask. If this is the case we attempt to make sense of the contents as
469 // text. This is pretty unfortunate since it means we have to actually
470 // copy the data to see if it is available, but at least this path
471 // shouldn't be hit for conforming programs.
472 std::vector
< ::Atom
> types
= GetTextAtoms();
473 for (std::vector
< ::Atom
>::const_iterator it
= types
.begin();
474 it
!= types
.end(); ++it
) {
476 if (receiver
->PerformBlockingConvertSelection(*it
,
487 return TargetList(out
, &atom_cache_
);
490 std::vector
< ::Atom
> Clipboard::AuraX11Details::GetTextAtoms() const {
491 return GetTextAtomsFrom(&atom_cache_
);
494 std::vector
< ::Atom
> Clipboard::AuraX11Details::GetAtomsForFormat(
495 const Clipboard::FormatType
& format
) {
496 std::vector
< ::Atom
> atoms
;
497 atoms
.push_back(atom_cache_
.GetAtom(format
.ToString().c_str()));
501 void Clipboard::AuraX11Details::Clear(ClipboardType type
) {
502 if (type
== CLIPBOARD_TYPE_COPY_PASTE
)
503 clipboard_owner_
.ClearSelectionOwner();
505 primary_owner_
.ClearSelectionOwner();
508 void Clipboard::AuraX11Details::StoreCopyPasteDataAndWait() {
509 ::Atom selection
= GetCopyPasteSelection();
510 if (XGetSelectionOwner(x_display_
, selection
) != x_window_
)
513 ::Atom clipboard_manager_atom
= atom_cache_
.GetAtom(kClipboardManager
);
514 if (XGetSelectionOwner(x_display_
, clipboard_manager_atom
) == None
)
517 const SelectionFormatMap
& format_map
= LookupStorageForAtom(selection
);
518 if (format_map
.size() == 0)
520 std::vector
<Atom
> targets
= format_map
.GetTypes();
522 base::TimeTicks start
= base::TimeTicks::Now();
523 clipboard_manager_requestor_
.PerformBlockingConvertSelectionWithParameter(
524 atom_cache_
.GetAtom(kSaveTargets
), targets
);
525 UMA_HISTOGRAM_TIMES("Clipboard.X11StoreCopyPasteDuration",
526 base::TimeTicks::Now() - start
);
529 bool Clipboard::AuraX11Details::CanDispatchEvent(const PlatformEvent
& event
) {
530 return event
->xany
.window
== x_window_
;
533 uint32_t Clipboard::AuraX11Details::DispatchEvent(const PlatformEvent
& xev
) {
535 case SelectionRequest
: {
536 if (xev
->xselectionrequest
.selection
== XA_PRIMARY
) {
537 primary_owner_
.OnSelectionRequest(xev
->xselectionrequest
);
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
->xselectionrequest
);
546 case SelectionNotify
: {
547 ::Atom selection
= xev
->xselection
.selection
;
548 if (selection
== XA_PRIMARY
)
549 primary_requestor_
.OnSelectionNotify(*xev
);
550 else if (selection
== GetCopyPasteSelection())
551 clipboard_requestor_
.OnSelectionNotify(*xev
);
552 else if (selection
== atom_cache_
.GetAtom(kClipboardManager
))
553 clipboard_manager_requestor_
.OnSelectionNotify(*xev
);
556 case SelectionClear
: {
557 if (xev
->xselectionclear
.selection
== XA_PRIMARY
) {
558 primary_owner_
.OnSelectionClear(xev
->xselectionclear
);
560 // We should not get requests for the CLIPBOARD_MANAGER selection
561 // because we never take ownership of it.
562 DCHECK_EQ(GetCopyPasteSelection(), xev
->xselection
.selection
);
563 clipboard_owner_
.OnSelectionClear(xev
->xselectionclear
);
571 return POST_DISPATCH_NONE
;
574 ///////////////////////////////////////////////////////////////////////////////
577 Clipboard::Clipboard()
578 : aurax11_details_(new AuraX11Details
) {
579 DCHECK(CalledOnValidThread());
582 Clipboard::~Clipboard() {
583 DCHECK(CalledOnValidThread());
585 aurax11_details_
->StoreCopyPasteDataAndWait();
588 void Clipboard::WriteObjects(ClipboardType type
, const ObjectMap
& objects
) {
589 DCHECK(CalledOnValidThread());
590 DCHECK(IsSupportedClipboardType(type
));
592 aurax11_details_
->CreateNewClipboardData();
593 for (ObjectMap::const_iterator iter
= objects
.begin();
594 iter
!= objects
.end(); ++iter
) {
595 DispatchObject(static_cast<ObjectType
>(iter
->first
), iter
->second
);
597 aurax11_details_
->TakeOwnershipOfSelection(type
);
599 if (type
== CLIPBOARD_TYPE_COPY_PASTE
) {
600 ObjectMap::const_iterator text_iter
= objects
.find(CBF_TEXT
);
601 if (text_iter
!= objects
.end()) {
602 aurax11_details_
->CreateNewClipboardData();
603 const ObjectMapParams
& params_vector
= text_iter
->second
;
604 if (params_vector
.size()) {
605 const ObjectMapParam
& char_vector
= params_vector
[0];
606 if (char_vector
.size())
607 WriteText(&char_vector
.front(), char_vector
.size());
609 aurax11_details_
->TakeOwnershipOfSelection(CLIPBOARD_TYPE_SELECTION
);
614 bool Clipboard::IsFormatAvailable(const FormatType
& format
,
615 ClipboardType type
) const {
616 DCHECK(CalledOnValidThread());
617 DCHECK(IsSupportedClipboardType(type
));
619 TargetList target_list
= aurax11_details_
->WaitAndGetTargetsList(type
);
620 if (format
.Equals(GetPlainTextFormatType()) ||
621 format
.Equals(GetUrlFormatType())) {
622 return target_list
.ContainsText();
624 return target_list
.ContainsFormat(format
);
627 void Clipboard::Clear(ClipboardType type
) {
628 DCHECK(CalledOnValidThread());
629 DCHECK(IsSupportedClipboardType(type
));
630 aurax11_details_
->Clear(type
);
633 void Clipboard::ReadAvailableTypes(ClipboardType type
,
634 std::vector
<base::string16
>* types
,
635 bool* contains_filenames
) const {
636 DCHECK(CalledOnValidThread());
637 if (!types
|| !contains_filenames
) {
642 TargetList target_list
= aurax11_details_
->WaitAndGetTargetsList(type
);
646 if (target_list
.ContainsText())
647 types
->push_back(base::UTF8ToUTF16(kMimeTypeText
));
648 if (target_list
.ContainsFormat(GetHtmlFormatType()))
649 types
->push_back(base::UTF8ToUTF16(kMimeTypeHTML
));
650 if (target_list
.ContainsFormat(GetRtfFormatType()))
651 types
->push_back(base::UTF8ToUTF16(kMimeTypeRTF
));
652 if (target_list
.ContainsFormat(GetBitmapFormatType()))
653 types
->push_back(base::UTF8ToUTF16(kMimeTypePNG
));
654 *contains_filenames
= false;
656 SelectionData
data(aurax11_details_
->RequestAndWaitForTypes(
657 type
, aurax11_details_
->GetAtomsForFormat(GetWebCustomDataFormatType())));
659 ReadCustomDataTypes(data
.GetData(), data
.GetSize(), types
);
662 void Clipboard::ReadText(ClipboardType type
, base::string16
* result
) const {
663 DCHECK(CalledOnValidThread());
665 SelectionData
data(aurax11_details_
->RequestAndWaitForTypes(
666 type
, aurax11_details_
->GetTextAtoms()));
667 if (data
.IsValid()) {
668 std::string text
= data
.GetText();
669 *result
= base::UTF8ToUTF16(text
);
673 void Clipboard::ReadAsciiText(ClipboardType type
, std::string
* result
) const {
674 DCHECK(CalledOnValidThread());
676 SelectionData
data(aurax11_details_
->RequestAndWaitForTypes(
677 type
, aurax11_details_
->GetTextAtoms()));
679 result
->assign(data
.GetText());
682 // TODO(estade): handle different charsets.
683 // TODO(port): set *src_url.
684 void Clipboard::ReadHTML(ClipboardType type
,
685 base::string16
* markup
,
686 std::string
* src_url
,
687 uint32
* fragment_start
,
688 uint32
* fragment_end
) const {
689 DCHECK(CalledOnValidThread());
696 SelectionData
data(aurax11_details_
->RequestAndWaitForTypes(
697 type
, aurax11_details_
->GetAtomsForFormat(GetHtmlFormatType())));
698 if (data
.IsValid()) {
699 *markup
= data
.GetHtml();
702 DCHECK(markup
->length() <= kuint32max
);
703 *fragment_end
= static_cast<uint32
>(markup
->length());
707 void Clipboard::ReadRTF(ClipboardType type
, std::string
* result
) const {
708 DCHECK(CalledOnValidThread());
710 SelectionData
data(aurax11_details_
->RequestAndWaitForTypes(
711 type
, aurax11_details_
->GetAtomsForFormat(GetRtfFormatType())));
713 data
.AssignTo(result
);
716 SkBitmap
Clipboard::ReadImage(ClipboardType type
) const {
717 DCHECK(CalledOnValidThread());
719 SelectionData
data(aurax11_details_
->RequestAndWaitForTypes(
720 type
, aurax11_details_
->GetAtomsForFormat(GetBitmapFormatType())));
721 if (data
.IsValid()) {
723 if (gfx::PNGCodec::Decode(data
.GetData(), data
.GetSize(), &bitmap
))
724 return SkBitmap(bitmap
);
730 void Clipboard::ReadCustomData(ClipboardType clipboard_type
,
731 const base::string16
& type
,
732 base::string16
* result
) const {
733 DCHECK(CalledOnValidThread());
735 SelectionData
data(aurax11_details_
->RequestAndWaitForTypes(
737 aurax11_details_
->GetAtomsForFormat(GetWebCustomDataFormatType())));
739 ReadCustomDataForType(data
.GetData(), data
.GetSize(), type
, result
);
742 void Clipboard::ReadBookmark(base::string16
* title
, std::string
* url
) const {
743 DCHECK(CalledOnValidThread());
744 // TODO(erg): This was left NOTIMPLEMENTED() in the gtk port too.
748 void Clipboard::ReadData(const FormatType
& format
, std::string
* result
) const {
749 DCHECK(CalledOnValidThread());
751 SelectionData
data(aurax11_details_
->RequestAndWaitForTypes(
752 CLIPBOARD_TYPE_COPY_PASTE
, aurax11_details_
->GetAtomsForFormat(format
)));
754 data
.AssignTo(result
);
757 uint64
Clipboard::GetSequenceNumber(ClipboardType type
) {
758 DCHECK(CalledOnValidThread());
759 if (type
== CLIPBOARD_TYPE_COPY_PASTE
)
760 return SelectionChangeObserver::GetInstance()->clipboard_sequence_number();
762 return SelectionChangeObserver::GetInstance()->primary_sequence_number();
765 void Clipboard::WriteText(const char* text_data
, size_t text_len
) {
766 std::string
str(text_data
, text_len
);
767 scoped_refptr
<base::RefCountedMemory
> mem(
768 base::RefCountedString::TakeString(&str
));
770 aurax11_details_
->InsertMapping(kMimeTypeText
, mem
);
771 aurax11_details_
->InsertMapping(kText
, mem
);
772 aurax11_details_
->InsertMapping(kString
, mem
);
773 aurax11_details_
->InsertMapping(kUtf8String
, mem
);
776 void Clipboard::WriteHTML(const char* markup_data
,
778 const char* url_data
,
780 // TODO(estade): We need to expand relative links with |url_data|.
781 static const char* html_prefix
= "<meta http-equiv=\"content-type\" "
782 "content=\"text/html; charset=utf-8\">";
783 std::string data
= html_prefix
;
784 data
+= std::string(markup_data
, markup_len
);
785 // Some programs expect NULL-terminated data. See http://crbug.com/42624
788 scoped_refptr
<base::RefCountedMemory
> mem(
789 base::RefCountedString::TakeString(&data
));
790 aurax11_details_
->InsertMapping(kMimeTypeHTML
, mem
);
793 void Clipboard::WriteRTF(const char* rtf_data
, size_t data_len
) {
794 WriteData(GetRtfFormatType(), rtf_data
, data_len
);
797 void Clipboard::WriteBookmark(const char* title_data
,
799 const char* url_data
,
801 // Write as a mozilla url (UTF16: URL, newline, title).
802 base::string16 url
= base::UTF8ToUTF16(std::string(url_data
, url_len
) + "\n");
803 base::string16 title
= base::UTF8ToUTF16(std::string(title_data
, title_len
));
805 std::vector
<unsigned char> data
;
806 ui::AddString16ToVector(url
, &data
);
807 ui::AddString16ToVector(title
, &data
);
808 scoped_refptr
<base::RefCountedMemory
> mem(
809 base::RefCountedBytes::TakeVector(&data
));
811 aurax11_details_
->InsertMapping(kMimeTypeMozillaURL
, mem
);
814 // Write an extra flavor that signifies WebKit was the last to modify the
815 // pasteboard. This flavor has no data.
816 void Clipboard::WriteWebSmartPaste() {
818 aurax11_details_
->InsertMapping(
819 kMimeTypeWebkitSmartPaste
,
820 scoped_refptr
<base::RefCountedMemory
>(
821 base::RefCountedString::TakeString(&empty
)));
824 void Clipboard::WriteBitmap(const SkBitmap
& bitmap
) {
825 // Encode the bitmap as a PNG for transport.
826 std::vector
<unsigned char> output
;
827 if (gfx::PNGCodec::FastEncodeBGRASkBitmap(bitmap
, false, &output
)) {
828 aurax11_details_
->InsertMapping(kMimeTypePNG
,
829 base::RefCountedBytes::TakeVector(
834 void Clipboard::WriteData(const FormatType
& format
,
835 const char* data_data
,
837 // We assume that certain mapping types are only written by trusted code.
838 // Therefore we must upkeep their integrity.
839 if (format
.Equals(GetBitmapFormatType()))
842 std::vector
<unsigned char> bytes(data_data
, data_data
+ data_len
);
843 scoped_refptr
<base::RefCountedMemory
> mem(
844 base::RefCountedBytes::TakeVector(&bytes
));
845 aurax11_details_
->InsertMapping(format
.ToString(), mem
);
849 Clipboard::FormatType
Clipboard::GetFormatType(
850 const std::string
& format_string
) {
851 return FormatType::Deserialize(format_string
);
855 const Clipboard::FormatType
& Clipboard::GetUrlFormatType() {
856 CR_DEFINE_STATIC_LOCAL(FormatType
, type
, (kMimeTypeURIList
));
861 const Clipboard::FormatType
& Clipboard::GetUrlWFormatType() {
862 return GetUrlFormatType();
866 const Clipboard::FormatType
& Clipboard::GetPlainTextFormatType() {
867 CR_DEFINE_STATIC_LOCAL(FormatType
, type
, (kMimeTypeText
));
872 const Clipboard::FormatType
& Clipboard::GetPlainTextWFormatType() {
873 return GetPlainTextFormatType();
877 const Clipboard::FormatType
& Clipboard::GetFilenameFormatType() {
878 CR_DEFINE_STATIC_LOCAL(FormatType
, type
, (kMimeTypeFilename
));
883 const Clipboard::FormatType
& Clipboard::GetFilenameWFormatType() {
884 return Clipboard::GetFilenameFormatType();
888 const Clipboard::FormatType
& Clipboard::GetHtmlFormatType() {
889 CR_DEFINE_STATIC_LOCAL(FormatType
, type
, (kMimeTypeHTML
));
894 const Clipboard::FormatType
& Clipboard::GetRtfFormatType() {
895 CR_DEFINE_STATIC_LOCAL(FormatType
, type
, (kMimeTypeRTF
));
900 const Clipboard::FormatType
& Clipboard::GetBitmapFormatType() {
901 CR_DEFINE_STATIC_LOCAL(FormatType
, type
, (kMimeTypePNG
));
906 const Clipboard::FormatType
& Clipboard::GetWebKitSmartPasteFormatType() {
907 CR_DEFINE_STATIC_LOCAL(FormatType
, type
, (kMimeTypeWebkitSmartPaste
));
912 const Clipboard::FormatType
& Clipboard::GetWebCustomDataFormatType() {
913 CR_DEFINE_STATIC_LOCAL(FormatType
, type
, (kMimeTypeWebCustomData
));
918 const Clipboard::FormatType
& Clipboard::GetPepperCustomDataFormatType() {
919 CR_DEFINE_STATIC_LOCAL(FormatType
, type
, (kMimeTypePepperCustomData
));