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/message_loop/message_pump_observer.h"
19 #include "base/message_loop/message_pump_x11.h"
20 #include "base/stl_util.h"
21 #include "base/strings/utf_string_conversions.h"
22 #include "third_party/skia/include/core/SkBitmap.h"
23 #include "ui/base/clipboard/custom_data_helper.h"
24 #include "ui/base/x/selection_owner.h"
25 #include "ui/base/x/selection_requestor.h"
26 #include "ui/base/x/selection_utils.h"
27 #include "ui/base/x/x11_util.h"
28 #include "ui/gfx/codec/png_codec.h"
29 #include "ui/gfx/size.h"
30 #include "ui/gfx/x/x11_atom_cache.h"
36 const char kClipboard
[] = "CLIPBOARD";
37 const char kMimeTypeFilename
[] = "chromium/filename";
38 const char kMimeTypePepperCustomData
[] = "chromium/x-pepper-custom-data";
39 const char kMimeTypeWebkitSmartPaste
[] = "chromium/x-webkit-paste";
40 const char kTargets
[] = "TARGETS";
42 const char* kAtomsToCache
[] = {
44 Clipboard::kMimeTypePNG
,
47 kMimeTypeWebkitSmartPaste
,
55 ///////////////////////////////////////////////////////////////////////////////
57 // Uses the XFixes API to provide sequence numbers for GetSequenceNumber().
58 class SelectionChangeObserver
: public base::MessagePumpObserver
{
60 static SelectionChangeObserver
* GetInstance();
62 uint64
clipboard_sequence_number() const {
63 return clipboard_sequence_number_
;
65 uint64
primary_sequence_number() const { return primary_sequence_number_
; }
68 friend struct DefaultSingletonTraits
<SelectionChangeObserver
>;
70 SelectionChangeObserver();
71 virtual ~SelectionChangeObserver();
73 // Overridden from base::MessagePumpObserver:
74 virtual base::EventStatus
WillProcessEvent(
75 const base::NativeEvent
& event
) OVERRIDE
;
76 virtual void DidProcessEvent(
77 const base::NativeEvent
& event
) OVERRIDE
{}
81 uint64 clipboard_sequence_number_
;
82 uint64 primary_sequence_number_
;
84 DISALLOW_COPY_AND_ASSIGN(SelectionChangeObserver
);
87 SelectionChangeObserver::SelectionChangeObserver()
89 clipboard_atom_(None
),
90 clipboard_sequence_number_(0),
91 primary_sequence_number_(0) {
93 if (XFixesQueryExtension(gfx::GetXDisplay(), &event_base_
, &ignored
)) {
94 clipboard_atom_
= XInternAtom(gfx::GetXDisplay(), kClipboard
, false);
95 XFixesSelectSelectionInput(gfx::GetXDisplay(), GetX11RootWindow(),
97 XFixesSetSelectionOwnerNotifyMask
|
98 XFixesSelectionWindowDestroyNotifyMask
|
99 XFixesSelectionClientCloseNotifyMask
);
100 // This seems to be semi-optional. For some reason, registering for any
101 // selection notify events seems to subscribe us to events for both the
102 // primary and the clipboard buffers. Register anyway just to be safe.
103 XFixesSelectSelectionInput(gfx::GetXDisplay(), GetX11RootWindow(),
105 XFixesSetSelectionOwnerNotifyMask
|
106 XFixesSelectionWindowDestroyNotifyMask
|
107 XFixesSelectionClientCloseNotifyMask
);
109 base::MessagePumpX11::Current()->AddObserver(this);
113 SelectionChangeObserver::~SelectionChangeObserver() {
114 // We are a singleton; we will outlive our message pump.
117 SelectionChangeObserver
* SelectionChangeObserver::GetInstance() {
118 return Singleton
<SelectionChangeObserver
>::get();
121 base::EventStatus
SelectionChangeObserver::WillProcessEvent(
122 const base::NativeEvent
& event
) {
123 if (event
->type
== event_base_
+ XFixesSelectionNotify
) {
124 XFixesSelectionNotifyEvent
* ev
=
125 reinterpret_cast<XFixesSelectionNotifyEvent
*>(event
);
126 if (ev
->selection
== clipboard_atom_
) {
127 clipboard_sequence_number_
++;
128 } else if (ev
->selection
== XA_PRIMARY
) {
129 primary_sequence_number_
++;
131 DLOG(ERROR
) << "Unexpected selection atom: " << ev
->selection
;
134 return base::EVENT_CONTINUE
;
137 ///////////////////////////////////////////////////////////////////////////////
139 // Represents a list of possible return types. Copy constructable.
142 typedef std::vector
< ::Atom
> AtomVector
;
144 TargetList(const AtomVector
& target_list
, X11AtomCache
* atom_cache
);
146 const AtomVector
& target_list() { return target_list_
; }
148 bool ContainsText() const;
149 bool ContainsFormat(const Clipboard::FormatType
& format_type
) const;
150 bool ContainsAtom(::Atom atom
) const;
153 AtomVector target_list_
;
154 X11AtomCache
* atom_cache_
;
157 TargetList::TargetList(const AtomVector
& target_list
,
158 X11AtomCache
* atom_cache
)
159 : target_list_(target_list
),
160 atom_cache_(atom_cache
) {
163 bool TargetList::ContainsText() const {
164 std::vector
< ::Atom
> atoms
= GetTextAtomsFrom(atom_cache_
);
165 for (std::vector
< ::Atom
>::const_iterator it
= atoms
.begin();
166 it
!= atoms
.end(); ++it
) {
167 if (ContainsAtom(*it
))
174 bool TargetList::ContainsFormat(
175 const Clipboard::FormatType
& format_type
) const {
176 ::Atom atom
= atom_cache_
->GetAtom(format_type
.ToString().c_str());
177 return ContainsAtom(atom
);
180 bool TargetList::ContainsAtom(::Atom atom
) const {
181 return find(target_list_
.begin(), target_list_
.end(), atom
)
182 != target_list_
.end();
187 ///////////////////////////////////////////////////////////////////////////////
189 // I would love for the FormatType to really be a wrapper around an X11 ::Atom,
190 // but there are a few problems. Chromeos unit tests spawn a new X11 server for
191 // each test, so Atom numeric values don't persist across tests. We could still
192 // maybe deal with that if we didn't have static accessor methods everywhere.
194 Clipboard::FormatType::FormatType() {
197 Clipboard::FormatType::FormatType(const std::string
& native_format
)
198 : data_(native_format
) {
201 Clipboard::FormatType::~FormatType() {
204 std::string
Clipboard::FormatType::Serialize() const {
209 Clipboard::FormatType
Clipboard::FormatType::Deserialize(
210 const std::string
& serialization
) {
211 return FormatType(serialization
);
214 bool Clipboard::FormatType::operator<(const FormatType
& other
) const {
215 return data_
< other
.data_
;
218 bool Clipboard::FormatType::Equals(const FormatType
& other
) const {
219 return data_
== other
.data_
;
222 ///////////////////////////////////////////////////////////////////////////////
223 // Clipboard::AuraX11Details
225 // Private implementation of our X11 integration. Keeps X11 headers out of the
226 // majority of chrome, which break badly.
227 class Clipboard::AuraX11Details
: public base::MessagePumpDispatcher
{
230 virtual ~AuraX11Details();
232 X11AtomCache
* atom_cache() { return &atom_cache_
; }
234 // Returns the X11 type that we pass to various XSelection functions for the
236 ::Atom
LookupSelectionForClipboardType(ClipboardType type
) const;
238 // Returns the object which is responsible for communication on |type|.
239 SelectionRequestor
* GetSelectionRequestorForClipboardType(ClipboardType type
);
241 // Finds the SelectionFormatMap for the incoming selection atom.
242 const SelectionFormatMap
& LookupStorageForAtom(::Atom atom
);
244 // As we need to collect all the data types before we tell X11 that we own a
245 // particular selection, we create a temporary clipboard mapping that
246 // InsertMapping writes to. Then we commit it in TakeOwnershipOfSelection,
247 // where we save it in one of the clipboard data slots.
248 void CreateNewClipboardData();
250 // Inserts a mapping into clipboard_data_.
251 void InsertMapping(const std::string
& key
,
252 const scoped_refptr
<base::RefCountedMemory
>& memory
);
254 // Moves the temporary |clipboard_data_| to the long term data storage for
256 void TakeOwnershipOfSelection(ClipboardType type
);
258 // Returns the first of |types| offered by the current selection holder in
259 // |data_out|, or returns NULL if none of those types are available.
261 // If the selection holder is us, this call is synchronous and we pull
262 // the data out of |clipboard_selection_| or |primary_selection_|. If the
263 // selection holder is some other window, we spin up a nested message loop
264 // and do the asynchronous dance with whatever application is holding the
266 ui::SelectionData
RequestAndWaitForTypes(ClipboardType type
,
267 const std::vector
< ::Atom
>& types
);
269 // Retrieves the list of possible data types the current clipboard owner has.
271 // If the selection holder is us, this is synchronous, otherwise this runs a
272 // blocking message loop.
273 TargetList
WaitAndGetTargetsList(ClipboardType type
);
275 // Returns a list of all text atoms that we handle.
276 std::vector
< ::Atom
> GetTextAtoms() const;
278 // Returns a vector with a |format| converted to an X11 atom.
279 std::vector
< ::Atom
> GetAtomsForFormat(const Clipboard::FormatType
& format
);
281 // Clears a certain clipboard type.
282 void Clear(ClipboardType type
);
285 // Overridden from base::MessagePumpDispatcher:
286 virtual bool Dispatch(const base::NativeEvent
& event
) OVERRIDE
;
290 ::Window x_root_window_
;
292 // Input-only window used as a selection owner.
295 X11AtomCache atom_cache_
;
297 // Objects which request and receive selection data.
298 SelectionRequestor clipboard_requestor_
;
299 SelectionRequestor primary_requestor_
;
301 // Temporary target map that we write to during DispatchObects.
302 SelectionFormatMap clipboard_data_
;
304 // Objects which offer selection data to other windows.
305 SelectionOwner clipboard_owner_
;
306 SelectionOwner primary_owner_
;
308 DISALLOW_COPY_AND_ASSIGN(AuraX11Details
);
311 Clipboard::AuraX11Details::AuraX11Details()
312 : x_display_(gfx::GetXDisplay()),
313 x_root_window_(DefaultRootWindow(x_display_
)),
314 x_window_(XCreateWindow(
315 x_display_
, x_root_window_
,
316 -100, -100, 10, 10, // x, y, width, height
318 CopyFromParent
, // depth
320 CopyFromParent
, // visual
323 atom_cache_(x_display_
, kAtomsToCache
),
324 clipboard_requestor_(x_display_
, x_window_
,
325 atom_cache_
.GetAtom(kClipboard
)),
326 primary_requestor_(x_display_
, x_window_
, XA_PRIMARY
),
327 clipboard_owner_(x_display_
, x_window_
, atom_cache_
.GetAtom(kClipboard
)),
328 primary_owner_(x_display_
, x_window_
, XA_PRIMARY
) {
329 // We don't know all possible MIME types at compile time.
330 atom_cache_
.allow_uncached_atoms();
332 XStoreName(x_display_
, x_window_
, "Chromium clipboard");
333 XSelectInput(x_display_
, x_window_
, PropertyChangeMask
);
335 base::MessagePumpX11::Current()->AddDispatcherForWindow(this, x_window_
);
338 Clipboard::AuraX11Details::~AuraX11Details() {
339 base::MessagePumpX11::Current()->RemoveDispatcherForWindow(x_window_
);
341 XDestroyWindow(x_display_
, x_window_
);
344 ::Atom
Clipboard::AuraX11Details::LookupSelectionForClipboardType(
345 ClipboardType type
) const {
346 if (type
== CLIPBOARD_TYPE_COPY_PASTE
)
347 return atom_cache_
.GetAtom(kClipboard
);
352 const SelectionFormatMap
& Clipboard::AuraX11Details::LookupStorageForAtom(
354 if (atom
== XA_PRIMARY
)
355 return primary_owner_
.selection_format_map();
357 DCHECK_EQ(atom_cache_
.GetAtom(kClipboard
), atom
);
358 return clipboard_owner_
.selection_format_map();
361 ui::SelectionRequestor
*
362 Clipboard::AuraX11Details::GetSelectionRequestorForClipboardType(
363 ClipboardType type
) {
364 if (type
== CLIPBOARD_TYPE_COPY_PASTE
)
365 return &clipboard_requestor_
;
367 return &primary_requestor_
;
370 void Clipboard::AuraX11Details::CreateNewClipboardData() {
371 clipboard_data_
= SelectionFormatMap();
374 void Clipboard::AuraX11Details::InsertMapping(
375 const std::string
& key
,
376 const scoped_refptr
<base::RefCountedMemory
>& memory
) {
377 ::Atom atom_key
= atom_cache_
.GetAtom(key
.c_str());
378 clipboard_data_
.Insert(atom_key
, memory
);
381 void Clipboard::AuraX11Details::TakeOwnershipOfSelection(ClipboardType type
) {
382 if (type
== CLIPBOARD_TYPE_COPY_PASTE
)
383 return clipboard_owner_
.TakeOwnershipOfSelection(clipboard_data_
);
385 return primary_owner_
.TakeOwnershipOfSelection(clipboard_data_
);
388 SelectionData
Clipboard::AuraX11Details::RequestAndWaitForTypes(
390 const std::vector
< ::Atom
>& types
) {
391 ::Atom selection_name
= LookupSelectionForClipboardType(type
);
392 if (XGetSelectionOwner(x_display_
, selection_name
) == x_window_
) {
393 // We can local fastpath instead of playing the nested message loop game
394 // with the X server.
395 const SelectionFormatMap
& format_map
= LookupStorageForAtom(selection_name
);
397 for (std::vector
< ::Atom
>::const_iterator it
= types
.begin();
398 it
!= types
.end(); ++it
) {
399 SelectionFormatMap::const_iterator format_map_it
= format_map
.find(*it
);
400 if (format_map_it
!= format_map
.end())
401 return SelectionData(format_map_it
->first
, format_map_it
->second
);
404 TargetList targets
= WaitAndGetTargetsList(type
);
405 SelectionRequestor
* receiver
= GetSelectionRequestorForClipboardType(type
);
407 std::vector
< ::Atom
> intersection
;
408 ui::GetAtomIntersection(types
, targets
.target_list(), &intersection
);
409 return receiver
->RequestAndWaitForTypes(intersection
);
412 return SelectionData();
415 TargetList
Clipboard::AuraX11Details::WaitAndGetTargetsList(
416 ClipboardType type
) {
417 ::Atom selection_name
= LookupSelectionForClipboardType(type
);
418 std::vector
< ::Atom
> out
;
419 if (XGetSelectionOwner(x_display_
, selection_name
) == x_window_
) {
420 // We can local fastpath and return the list of local targets.
421 const SelectionFormatMap
& format_map
= LookupStorageForAtom(selection_name
);
423 for (SelectionFormatMap::const_iterator it
= format_map
.begin();
424 it
!= format_map
.end(); ++it
) {
425 out
.push_back(it
->first
);
428 scoped_refptr
<base::RefCountedMemory
> data
;
429 size_t out_data_items
= 0;
430 ::Atom out_type
= None
;
432 SelectionRequestor
* receiver
= GetSelectionRequestorForClipboardType(type
);
433 if (receiver
->PerformBlockingConvertSelection(atom_cache_
.GetAtom(kTargets
),
438 const ::Atom
* atom_array
= reinterpret_cast<const ::Atom
*>(data
->front());
439 for (size_t i
= 0; i
< out_data_items
; ++i
)
440 out
.push_back(atom_array
[i
]);
442 // There was no target list. Most Java apps doesn't offer a TARGETS list,
443 // even though they AWT to. They will offer individual text types if you
444 // ask. If this is the case we attempt to make sense of the contents as
445 // text. This is pretty unfortunate since it means we have to actually
446 // copy the data to see if it is available, but at least this path
447 // shouldn't be hit for conforming programs.
448 std::vector
< ::Atom
> types
= GetTextAtoms();
449 for (std::vector
< ::Atom
>::const_iterator it
= types
.begin();
450 it
!= types
.end(); ++it
) {
452 if (receiver
->PerformBlockingConvertSelection(*it
,
464 return TargetList(out
, &atom_cache_
);
467 std::vector
< ::Atom
> Clipboard::AuraX11Details::GetTextAtoms() const {
468 return GetTextAtomsFrom(&atom_cache_
);
471 std::vector
< ::Atom
> Clipboard::AuraX11Details::GetAtomsForFormat(
472 const Clipboard::FormatType
& format
) {
473 std::vector
< ::Atom
> atoms
;
474 atoms
.push_back(atom_cache_
.GetAtom(format
.ToString().c_str()));
478 void Clipboard::AuraX11Details::Clear(ClipboardType type
) {
479 if (type
== CLIPBOARD_TYPE_COPY_PASTE
)
480 return clipboard_owner_
.Clear();
482 return primary_owner_
.Clear();
485 bool Clipboard::AuraX11Details::Dispatch(const base::NativeEvent
& event
) {
489 case SelectionRequest
: {
490 if (xev
->xselectionrequest
.selection
== XA_PRIMARY
)
491 primary_owner_
.OnSelectionRequest(xev
->xselectionrequest
);
493 clipboard_owner_
.OnSelectionRequest(xev
->xselectionrequest
);
496 case SelectionNotify
: {
497 if (xev
->xselection
.selection
== XA_PRIMARY
)
498 primary_requestor_
.OnSelectionNotify(xev
->xselection
);
500 clipboard_requestor_
.OnSelectionNotify(xev
->xselection
);
503 case SelectionClear
: {
504 if (xev
->xselectionclear
.selection
== XA_PRIMARY
)
505 primary_owner_
.OnSelectionClear(xev
->xselectionclear
);
507 clipboard_owner_
.OnSelectionClear(xev
->xselectionclear
);
517 ///////////////////////////////////////////////////////////////////////////////
520 Clipboard::Clipboard()
521 : aurax11_details_(new AuraX11Details
) {
522 DCHECK(CalledOnValidThread());
525 Clipboard::~Clipboard() {
526 DCHECK(CalledOnValidThread());
528 // TODO(erg): We need to do whatever the equivalent of
529 // gtk_clipboard_store(clipboard_) is here. When we shut down, we want the
530 // current selection to live on.
533 void Clipboard::WriteObjects(ClipboardType type
, const ObjectMap
& objects
) {
534 DCHECK(CalledOnValidThread());
535 DCHECK(IsSupportedClipboardType(type
));
537 aurax11_details_
->CreateNewClipboardData();
538 for (ObjectMap::const_iterator iter
= objects
.begin();
539 iter
!= objects
.end(); ++iter
) {
540 DispatchObject(static_cast<ObjectType
>(iter
->first
), iter
->second
);
542 aurax11_details_
->TakeOwnershipOfSelection(type
);
544 if (type
== CLIPBOARD_TYPE_COPY_PASTE
) {
545 ObjectMap::const_iterator text_iter
= objects
.find(CBF_TEXT
);
546 if (text_iter
!= objects
.end()) {
547 aurax11_details_
->CreateNewClipboardData();
548 const ObjectMapParam
& char_vector
= text_iter
->second
[0];
549 WriteText(&char_vector
.front(), char_vector
.size());
550 aurax11_details_
->TakeOwnershipOfSelection(CLIPBOARD_TYPE_SELECTION
);
555 bool Clipboard::IsFormatAvailable(const FormatType
& format
,
556 ClipboardType type
) const {
557 DCHECK(CalledOnValidThread());
558 DCHECK(IsSupportedClipboardType(type
));
560 TargetList target_list
= aurax11_details_
->WaitAndGetTargetsList(type
);
561 return target_list
.ContainsFormat(format
);
564 void Clipboard::Clear(ClipboardType type
) {
565 DCHECK(CalledOnValidThread());
566 DCHECK(IsSupportedClipboardType(type
));
567 aurax11_details_
->Clear(type
);
570 void Clipboard::ReadAvailableTypes(ClipboardType type
,
571 std::vector
<base::string16
>* types
,
572 bool* contains_filenames
) const {
573 DCHECK(CalledOnValidThread());
574 if (!types
|| !contains_filenames
) {
579 TargetList target_list
= aurax11_details_
->WaitAndGetTargetsList(type
);
583 if (target_list
.ContainsText())
584 types
->push_back(base::UTF8ToUTF16(kMimeTypeText
));
585 if (target_list
.ContainsFormat(GetHtmlFormatType()))
586 types
->push_back(base::UTF8ToUTF16(kMimeTypeHTML
));
587 if (target_list
.ContainsFormat(GetRtfFormatType()))
588 types
->push_back(base::UTF8ToUTF16(kMimeTypeRTF
));
589 if (target_list
.ContainsFormat(GetBitmapFormatType()))
590 types
->push_back(base::UTF8ToUTF16(kMimeTypePNG
));
591 *contains_filenames
= false;
593 SelectionData
data(aurax11_details_
->RequestAndWaitForTypes(
594 type
, aurax11_details_
->GetAtomsForFormat(GetWebCustomDataFormatType())));
596 ReadCustomDataTypes(data
.GetData(), data
.GetSize(), types
);
599 void Clipboard::ReadText(ClipboardType type
, base::string16
* result
) const {
600 DCHECK(CalledOnValidThread());
602 SelectionData
data(aurax11_details_
->RequestAndWaitForTypes(
603 type
, aurax11_details_
->GetTextAtoms()));
604 if (data
.IsValid()) {
605 std::string text
= data
.GetText();
606 *result
= base::UTF8ToUTF16(text
);
610 void Clipboard::ReadAsciiText(ClipboardType type
, std::string
* result
) const {
611 DCHECK(CalledOnValidThread());
613 SelectionData
data(aurax11_details_
->RequestAndWaitForTypes(
614 type
, aurax11_details_
->GetTextAtoms()));
616 result
->assign(data
.GetText());
619 // TODO(estade): handle different charsets.
620 // TODO(port): set *src_url.
621 void Clipboard::ReadHTML(ClipboardType type
,
622 base::string16
* markup
,
623 std::string
* src_url
,
624 uint32
* fragment_start
,
625 uint32
* fragment_end
) const {
626 DCHECK(CalledOnValidThread());
633 SelectionData
data(aurax11_details_
->RequestAndWaitForTypes(
634 type
, aurax11_details_
->GetAtomsForFormat(GetHtmlFormatType())));
635 if (data
.IsValid()) {
636 *markup
= data
.GetHtml();
639 DCHECK(markup
->length() <= kuint32max
);
640 *fragment_end
= static_cast<uint32
>(markup
->length());
644 void Clipboard::ReadRTF(ClipboardType type
, std::string
* result
) const {
645 DCHECK(CalledOnValidThread());
647 SelectionData
data(aurax11_details_
->RequestAndWaitForTypes(
648 type
, aurax11_details_
->GetAtomsForFormat(GetRtfFormatType())));
650 data
.AssignTo(result
);
653 SkBitmap
Clipboard::ReadImage(ClipboardType type
) const {
654 DCHECK(CalledOnValidThread());
656 SelectionData
data(aurax11_details_
->RequestAndWaitForTypes(
657 type
, aurax11_details_
->GetAtomsForFormat(GetBitmapFormatType())));
658 if (data
.IsValid()) {
660 if (gfx::PNGCodec::Decode(data
.GetData(), data
.GetSize(), &bitmap
))
661 return SkBitmap(bitmap
);
667 void Clipboard::ReadCustomData(ClipboardType clipboard_type
,
668 const base::string16
& type
,
669 base::string16
* result
) const {
670 DCHECK(CalledOnValidThread());
672 SelectionData
data(aurax11_details_
->RequestAndWaitForTypes(
674 aurax11_details_
->GetAtomsForFormat(GetWebCustomDataFormatType())));
676 ReadCustomDataForType(data
.GetData(), data
.GetSize(), type
, result
);
679 void Clipboard::ReadBookmark(base::string16
* title
, std::string
* url
) const {
680 DCHECK(CalledOnValidThread());
681 // TODO(erg): This was left NOTIMPLEMENTED() in the gtk port too.
685 void Clipboard::ReadData(const FormatType
& format
, std::string
* result
) const {
686 DCHECK(CalledOnValidThread());
688 SelectionData
data(aurax11_details_
->RequestAndWaitForTypes(
689 CLIPBOARD_TYPE_COPY_PASTE
, aurax11_details_
->GetAtomsForFormat(format
)));
691 data
.AssignTo(result
);
694 uint64
Clipboard::GetSequenceNumber(ClipboardType type
) {
695 DCHECK(CalledOnValidThread());
696 if (type
== CLIPBOARD_TYPE_COPY_PASTE
)
697 return SelectionChangeObserver::GetInstance()->clipboard_sequence_number();
699 return SelectionChangeObserver::GetInstance()->primary_sequence_number();
702 void Clipboard::WriteText(const char* text_data
, size_t text_len
) {
703 std::string
str(text_data
, text_len
);
704 scoped_refptr
<base::RefCountedMemory
> mem(
705 base::RefCountedString::TakeString(&str
));
707 aurax11_details_
->InsertMapping(kMimeTypeText
, mem
);
708 aurax11_details_
->InsertMapping(kText
, mem
);
709 aurax11_details_
->InsertMapping(kString
, mem
);
710 aurax11_details_
->InsertMapping(kUtf8String
, mem
);
713 void Clipboard::WriteHTML(const char* markup_data
,
715 const char* url_data
,
717 // TODO(estade): We need to expand relative links with |url_data|.
718 static const char* html_prefix
= "<meta http-equiv=\"content-type\" "
719 "content=\"text/html; charset=utf-8\">";
720 std::string data
= html_prefix
;
721 data
+= std::string(markup_data
, markup_len
);
722 // Some programs expect NULL-terminated data. See http://crbug.com/42624
725 scoped_refptr
<base::RefCountedMemory
> mem(
726 base::RefCountedString::TakeString(&data
));
727 aurax11_details_
->InsertMapping(kMimeTypeHTML
, mem
);
730 void Clipboard::WriteRTF(const char* rtf_data
, size_t data_len
) {
731 WriteData(GetRtfFormatType(), rtf_data
, data_len
);
734 void Clipboard::WriteBookmark(const char* title_data
,
736 const char* url_data
,
738 // Write as a mozilla url (UTF16: URL, newline, title).
739 base::string16 url
= base::UTF8ToUTF16(std::string(url_data
, url_len
) + "\n");
740 base::string16 title
= base::UTF8ToUTF16(std::string(title_data
, title_len
));
742 std::vector
<unsigned char> data
;
743 ui::AddString16ToVector(url
, &data
);
744 ui::AddString16ToVector(title
, &data
);
745 scoped_refptr
<base::RefCountedMemory
> mem(
746 base::RefCountedBytes::TakeVector(&data
));
748 aurax11_details_
->InsertMapping(kMimeTypeMozillaURL
, mem
);
751 // Write an extra flavor that signifies WebKit was the last to modify the
752 // pasteboard. This flavor has no data.
753 void Clipboard::WriteWebSmartPaste() {
754 aurax11_details_
->InsertMapping(kMimeTypeWebkitSmartPaste
,
755 scoped_refptr
<base::RefCountedMemory
>());
758 void Clipboard::WriteBitmap(const SkBitmap
& bitmap
) {
759 // Encode the bitmap as a PNG for transport.
760 std::vector
<unsigned char> output
;
761 if (gfx::PNGCodec::FastEncodeBGRASkBitmap(bitmap
, false, &output
)) {
762 aurax11_details_
->InsertMapping(kMimeTypePNG
,
763 base::RefCountedBytes::TakeVector(
768 void Clipboard::WriteData(const FormatType
& format
,
769 const char* data_data
,
771 // We assume that certain mapping types are only written by trusted code.
772 // Therefore we must upkeep their integrity.
773 if (format
.Equals(GetBitmapFormatType()))
776 std::vector
<unsigned char> bytes(data_data
, data_data
+ data_len
);
777 scoped_refptr
<base::RefCountedMemory
> mem(
778 base::RefCountedBytes::TakeVector(&bytes
));
779 aurax11_details_
->InsertMapping(format
.ToString(), mem
);
783 Clipboard::FormatType
Clipboard::GetFormatType(
784 const std::string
& format_string
) {
785 return FormatType::Deserialize(format_string
);
789 const Clipboard::FormatType
& Clipboard::GetUrlFormatType() {
790 CR_DEFINE_STATIC_LOCAL(FormatType
, type
, (kMimeTypeURIList
));
795 const Clipboard::FormatType
& Clipboard::GetUrlWFormatType() {
796 return GetUrlFormatType();
800 const Clipboard::FormatType
& Clipboard::GetPlainTextFormatType() {
801 CR_DEFINE_STATIC_LOCAL(FormatType
, type
, (kMimeTypeText
));
806 const Clipboard::FormatType
& Clipboard::GetPlainTextWFormatType() {
807 return GetPlainTextFormatType();
811 const Clipboard::FormatType
& Clipboard::GetFilenameFormatType() {
812 CR_DEFINE_STATIC_LOCAL(FormatType
, type
, (kMimeTypeFilename
));
817 const Clipboard::FormatType
& Clipboard::GetFilenameWFormatType() {
818 return Clipboard::GetFilenameFormatType();
822 const Clipboard::FormatType
& Clipboard::GetHtmlFormatType() {
823 CR_DEFINE_STATIC_LOCAL(FormatType
, type
, (kMimeTypeHTML
));
828 const Clipboard::FormatType
& Clipboard::GetRtfFormatType() {
829 CR_DEFINE_STATIC_LOCAL(FormatType
, type
, (kMimeTypeRTF
));
834 const Clipboard::FormatType
& Clipboard::GetBitmapFormatType() {
835 CR_DEFINE_STATIC_LOCAL(FormatType
, type
, (kMimeTypePNG
));
840 const Clipboard::FormatType
& Clipboard::GetWebKitSmartPasteFormatType() {
841 CR_DEFINE_STATIC_LOCAL(FormatType
, type
, (kMimeTypeWebkitSmartPaste
));
846 const Clipboard::FormatType
& Clipboard::GetWebCustomDataFormatType() {
847 CR_DEFINE_STATIC_LOCAL(FormatType
, type
, (kMimeTypeWebCustomData
));
852 const Clipboard::FormatType
& Clipboard::GetPepperCustomDataFormatType() {
853 CR_DEFINE_STATIC_LOCAL(FormatType
, type
, (kMimeTypePepperCustomData
));