Remove support for specifying version on command line.
[chromium-blink-merge.git] / ui / base / clipboard / clipboard_aurax11.cc
blob3be15de72181d74c8dff466fe732bd57303afd1a
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>
8 #include <X11/Xatom.h>
9 #include <list>
10 #include <set>
12 #include "base/basictypes.h"
13 #include "base/files/file_path.h"
14 #include "base/logging.h"
15 #include "base/memory/ref_counted_memory.h"
16 #include "base/memory/scoped_ptr.h"
17 #include "base/memory/singleton.h"
18 #include "base/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"
32 namespace ui {
34 namespace {
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[] = {
43 kClipboard,
44 Clipboard::kMimeTypePNG,
45 kMimeTypeFilename,
46 kMimeTypeMozillaURL,
47 kMimeTypeWebkitSmartPaste,
48 kString,
49 kTargets,
50 kText,
51 kUtf8String,
52 NULL
55 ///////////////////////////////////////////////////////////////////////////////
57 // Uses the XFixes API to provide sequence numbers for GetSequenceNumber().
58 class SelectionChangeObserver : public base::MessagePumpObserver {
59 public:
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_; }
67 private:
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 {}
79 int event_base_;
80 Atom clipboard_atom_;
81 uint64 clipboard_sequence_number_;
82 uint64 primary_sequence_number_;
84 DISALLOW_COPY_AND_ASSIGN(SelectionChangeObserver);
87 SelectionChangeObserver::SelectionChangeObserver()
88 : event_base_(-1),
89 clipboard_atom_(None),
90 clipboard_sequence_number_(0),
91 primary_sequence_number_(0) {
92 int ignored;
93 if (XFixesQueryExtension(gfx::GetXDisplay(), &event_base_, &ignored)) {
94 clipboard_atom_ = XInternAtom(gfx::GetXDisplay(), kClipboard, false);
95 XFixesSelectSelectionInput(gfx::GetXDisplay(), GetX11RootWindow(),
96 clipboard_atom_,
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(),
104 XA_PRIMARY,
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_++;
130 } else {
131 DLOG(ERROR) << "Unexpected selection atom: " << ev->selection;
134 return base::EVENT_CONTINUE;
137 ///////////////////////////////////////////////////////////////////////////////
139 // Represents a list of possible return types. Copy constructable.
140 class TargetList {
141 public:
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;
152 private:
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))
168 return true;
171 return false;
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();
185 } // namespace
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 {
205 return data_;
208 // static
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 {
228 public:
229 AuraX11Details();
230 virtual ~AuraX11Details();
232 X11AtomCache* atom_cache() { return &atom_cache_; }
234 // Returns the X11 type that we pass to various XSelection functions for the
235 // given type.
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
255 // |type|.
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
265 // selection.
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);
284 private:
285 // Overridden from base::MessagePumpDispatcher:
286 virtual bool Dispatch(const base::NativeEvent& event) OVERRIDE;
288 // Our X11 state.
289 Display* x_display_;
290 ::Window x_root_window_;
292 // Input-only window used as a selection owner.
293 ::Window x_window_;
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
317 0, // border width
318 CopyFromParent, // depth
319 InputOnly,
320 CopyFromParent, // visual
322 NULL)),
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);
349 return XA_PRIMARY;
352 const SelectionFormatMap& Clipboard::AuraX11Details::LookupStorageForAtom(
353 ::Atom atom) {
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_;
366 else
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_);
384 else
385 return primary_owner_.TakeOwnershipOfSelection(clipboard_data_);
388 SelectionData Clipboard::AuraX11Details::RequestAndWaitForTypes(
389 ClipboardType type,
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);
403 } else {
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);
427 } else {
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),
434 &data,
435 NULL,
436 &out_data_items,
437 &out_type)) {
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]);
441 } else {
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) {
451 ::Atom type = None;
452 if (receiver->PerformBlockingConvertSelection(*it,
453 NULL,
454 NULL,
455 NULL,
456 &type) &&
457 type == *it) {
458 out.push_back(*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()));
475 return atoms;
478 void Clipboard::AuraX11Details::Clear(ClipboardType type) {
479 if (type == CLIPBOARD_TYPE_COPY_PASTE)
480 return clipboard_owner_.Clear();
481 else
482 return primary_owner_.Clear();
485 bool Clipboard::AuraX11Details::Dispatch(const base::NativeEvent& event) {
486 XEvent* xev = event;
488 switch (xev->type) {
489 case SelectionRequest: {
490 if (xev->xselectionrequest.selection == XA_PRIMARY)
491 primary_owner_.OnSelectionRequest(xev->xselectionrequest);
492 else
493 clipboard_owner_.OnSelectionRequest(xev->xselectionrequest);
494 break;
496 case SelectionNotify: {
497 if (xev->xselection.selection == XA_PRIMARY)
498 primary_requestor_.OnSelectionNotify(xev->xselection);
499 else
500 clipboard_requestor_.OnSelectionNotify(xev->xselection);
501 break;
503 case SelectionClear: {
504 if (xev->xselectionclear.selection == XA_PRIMARY)
505 primary_owner_.OnSelectionClear(xev->xselectionclear);
506 else
507 clipboard_owner_.OnSelectionClear(xev->xselectionclear);
508 break;
510 default:
511 break;
514 return true;
517 ///////////////////////////////////////////////////////////////////////////////
518 // Clipboard
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) {
575 NOTREACHED();
576 return;
579 TargetList target_list = aurax11_details_->WaitAndGetTargetsList(type);
581 types->clear();
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())));
595 if (data.IsValid())
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()));
615 if (data.IsValid())
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());
627 markup->clear();
628 if (src_url)
629 src_url->clear();
630 *fragment_start = 0;
631 *fragment_end = 0;
633 SelectionData data(aurax11_details_->RequestAndWaitForTypes(
634 type, aurax11_details_->GetAtomsForFormat(GetHtmlFormatType())));
635 if (data.IsValid()) {
636 *markup = data.GetHtml();
638 *fragment_start = 0;
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())));
649 if (data.IsValid())
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()) {
659 SkBitmap bitmap;
660 if (gfx::PNGCodec::Decode(data.GetData(), data.GetSize(), &bitmap))
661 return SkBitmap(bitmap);
664 return SkBitmap();
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(
673 clipboard_type,
674 aurax11_details_->GetAtomsForFormat(GetWebCustomDataFormatType())));
675 if (data.IsValid())
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.
682 NOTIMPLEMENTED();
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)));
690 if (data.IsValid())
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();
698 else
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,
714 size_t markup_len,
715 const char* url_data,
716 size_t url_len) {
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
723 data += '\0';
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,
735 size_t title_len,
736 const char* url_data,
737 size_t url_len) {
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(
764 &output));
768 void Clipboard::WriteData(const FormatType& format,
769 const char* data_data,
770 size_t data_len) {
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()))
774 return;
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);
782 // static
783 Clipboard::FormatType Clipboard::GetFormatType(
784 const std::string& format_string) {
785 return FormatType::Deserialize(format_string);
788 // static
789 const Clipboard::FormatType& Clipboard::GetUrlFormatType() {
790 CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeURIList));
791 return type;
794 // static
795 const Clipboard::FormatType& Clipboard::GetUrlWFormatType() {
796 return GetUrlFormatType();
799 // static
800 const Clipboard::FormatType& Clipboard::GetPlainTextFormatType() {
801 CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeText));
802 return type;
805 // static
806 const Clipboard::FormatType& Clipboard::GetPlainTextWFormatType() {
807 return GetPlainTextFormatType();
810 // static
811 const Clipboard::FormatType& Clipboard::GetFilenameFormatType() {
812 CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeFilename));
813 return type;
816 // static
817 const Clipboard::FormatType& Clipboard::GetFilenameWFormatType() {
818 return Clipboard::GetFilenameFormatType();
821 // static
822 const Clipboard::FormatType& Clipboard::GetHtmlFormatType() {
823 CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeHTML));
824 return type;
827 // static
828 const Clipboard::FormatType& Clipboard::GetRtfFormatType() {
829 CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeRTF));
830 return type;
833 // static
834 const Clipboard::FormatType& Clipboard::GetBitmapFormatType() {
835 CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypePNG));
836 return type;
839 // static
840 const Clipboard::FormatType& Clipboard::GetWebKitSmartPasteFormatType() {
841 CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeWebkitSmartPaste));
842 return type;
845 // static
846 const Clipboard::FormatType& Clipboard::GetWebCustomDataFormatType() {
847 CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeWebCustomData));
848 return type;
851 // static
852 const Clipboard::FormatType& Clipboard::GetPepperCustomDataFormatType() {
853 CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypePepperCustomData));
854 return type;
857 } // namespace ui