• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "ui/base/clipboard/clipboard.h"
6 
7 #include <X11/extensions/Xfixes.h>
8 #include <X11/Xatom.h>
9 #include <list>
10 #include <set>
11 
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"
31 
32 namespace ui {
33 
34 namespace {
35 
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";
41 
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
53 };
54 
55 ///////////////////////////////////////////////////////////////////////////////
56 
57 // Uses the XFixes API to provide sequence numbers for GetSequenceNumber().
58 class SelectionChangeObserver : public base::MessagePumpObserver {
59  public:
60   static SelectionChangeObserver* GetInstance();
61 
clipboard_sequence_number() const62   uint64 clipboard_sequence_number() const {
63     return clipboard_sequence_number_;
64   }
primary_sequence_number() const65   uint64 primary_sequence_number() const { return primary_sequence_number_; }
66 
67  private:
68   friend struct DefaultSingletonTraits<SelectionChangeObserver>;
69 
70   SelectionChangeObserver();
71   virtual ~SelectionChangeObserver();
72 
73   // Overridden from base::MessagePumpObserver:
74   virtual base::EventStatus WillProcessEvent(
75       const base::NativeEvent& event) OVERRIDE;
DidProcessEvent(const base::NativeEvent & event)76   virtual void DidProcessEvent(
77       const base::NativeEvent& event) OVERRIDE {}
78 
79   int event_base_;
80   Atom clipboard_atom_;
81   uint64 clipboard_sequence_number_;
82   uint64 primary_sequence_number_;
83 
84   DISALLOW_COPY_AND_ASSIGN(SelectionChangeObserver);
85 };
86 
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);
108 
109     base::MessagePumpX11::Current()->AddObserver(this);
110   }
111 }
112 
~SelectionChangeObserver()113 SelectionChangeObserver::~SelectionChangeObserver() {
114   // We are a singleton; we will outlive our message pump.
115 }
116 
GetInstance()117 SelectionChangeObserver* SelectionChangeObserver::GetInstance() {
118   return Singleton<SelectionChangeObserver>::get();
119 }
120 
WillProcessEvent(const base::NativeEvent & event)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;
132     }
133   }
134   return base::EVENT_CONTINUE;
135 }
136 
137 ///////////////////////////////////////////////////////////////////////////////
138 
139 // Represents a list of possible return types. Copy constructable.
140 class TargetList {
141  public:
142   typedef std::vector< ::Atom> AtomVector;
143 
144   TargetList(const AtomVector& target_list, X11AtomCache* atom_cache);
145 
target_list()146   const AtomVector& target_list() { return target_list_; }
147 
148   bool ContainsText() const;
149   bool ContainsFormat(const Clipboard::FormatType& format_type) const;
150   bool ContainsAtom(::Atom atom) const;
151 
152  private:
153   AtomVector target_list_;
154   X11AtomCache* atom_cache_;
155 };
156 
TargetList(const AtomVector & target_list,X11AtomCache * atom_cache)157 TargetList::TargetList(const AtomVector& target_list,
158                        X11AtomCache* atom_cache)
159     : target_list_(target_list),
160       atom_cache_(atom_cache) {
161 }
162 
ContainsText() const163 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;
169   }
170 
171   return false;
172 }
173 
ContainsFormat(const Clipboard::FormatType & format_type) const174 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);
178 }
179 
ContainsAtom(::Atom atom) const180 bool TargetList::ContainsAtom(::Atom atom) const {
181   return find(target_list_.begin(), target_list_.end(), atom)
182       != target_list_.end();
183 }
184 
185 }  // namespace
186 
187 ///////////////////////////////////////////////////////////////////////////////
188 
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.
193 
FormatType()194 Clipboard::FormatType::FormatType() {
195 }
196 
FormatType(const std::string & native_format)197 Clipboard::FormatType::FormatType(const std::string& native_format)
198     : data_(native_format) {
199 }
200 
~FormatType()201 Clipboard::FormatType::~FormatType() {
202 }
203 
Serialize() const204 std::string Clipboard::FormatType::Serialize() const {
205   return data_;
206 }
207 
208 // static
Deserialize(const std::string & serialization)209 Clipboard::FormatType Clipboard::FormatType::Deserialize(
210     const std::string& serialization) {
211   return FormatType(serialization);
212 }
213 
operator <(const FormatType & other) const214 bool Clipboard::FormatType::operator<(const FormatType& other) const {
215   return data_ < other.data_;
216 }
217 
Equals(const FormatType & other) const218 bool Clipboard::FormatType::Equals(const FormatType& other) const {
219   return data_ == other.data_;
220 }
221 
222 ///////////////////////////////////////////////////////////////////////////////
223 // Clipboard::AuraX11Details
224 
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();
231 
atom_cache()232   X11AtomCache* atom_cache() { return &atom_cache_; }
233 
234   // Returns the X11 type that we pass to various XSelection functions for the
235   // given type.
236   ::Atom LookupSelectionForClipboardType(ClipboardType type) const;
237 
238   // Returns the object which is responsible for communication on |type|.
239   SelectionRequestor* GetSelectionRequestorForClipboardType(ClipboardType type);
240 
241   // Finds the SelectionFormatMap for the incoming selection atom.
242   const SelectionFormatMap& LookupStorageForAtom(::Atom atom);
243 
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();
249 
250   // Inserts a mapping into clipboard_data_.
251   void InsertMapping(const std::string& key,
252                      const scoped_refptr<base::RefCountedMemory>& memory);
253 
254   // Moves the temporary |clipboard_data_| to the long term data storage for
255   // |type|.
256   void TakeOwnershipOfSelection(ClipboardType type);
257 
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.
260   //
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);
268 
269   // Retrieves the list of possible data types the current clipboard owner has.
270   //
271   // If the selection holder is us, this is synchronous, otherwise this runs a
272   // blocking message loop.
273   TargetList WaitAndGetTargetsList(ClipboardType type);
274 
275   // Returns a list of all text atoms that we handle.
276   std::vector< ::Atom> GetTextAtoms() const;
277 
278   // Returns a vector with a |format| converted to an X11 atom.
279   std::vector< ::Atom> GetAtomsForFormat(const Clipboard::FormatType& format);
280 
281   // Clears a certain clipboard type.
282   void Clear(ClipboardType type);
283 
284  private:
285   // Overridden from base::MessagePumpDispatcher:
286   virtual bool Dispatch(const base::NativeEvent& event) OVERRIDE;
287 
288   // Our X11 state.
289   Display* x_display_;
290   ::Window x_root_window_;
291 
292   // Input-only window used as a selection owner.
293   ::Window x_window_;
294 
295   X11AtomCache atom_cache_;
296 
297   // Objects which request and receive selection data.
298   SelectionRequestor clipboard_requestor_;
299   SelectionRequestor primary_requestor_;
300 
301   // Temporary target map that we write to during DispatchObects.
302   SelectionFormatMap clipboard_data_;
303 
304   // Objects which offer selection data to other windows.
305   SelectionOwner clipboard_owner_;
306   SelectionOwner primary_owner_;
307 
308   DISALLOW_COPY_AND_ASSIGN(AuraX11Details);
309 };
310 
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
321           0,
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();
331 
332   XStoreName(x_display_, x_window_, "Chromium clipboard");
333   XSelectInput(x_display_, x_window_, PropertyChangeMask);
334 
335   base::MessagePumpX11::Current()->AddDispatcherForWindow(this, x_window_);
336 }
337 
~AuraX11Details()338 Clipboard::AuraX11Details::~AuraX11Details() {
339   base::MessagePumpX11::Current()->RemoveDispatcherForWindow(x_window_);
340 
341   XDestroyWindow(x_display_, x_window_);
342 }
343 
LookupSelectionForClipboardType(ClipboardType type) const344 ::Atom Clipboard::AuraX11Details::LookupSelectionForClipboardType(
345     ClipboardType type) const {
346   if (type == CLIPBOARD_TYPE_COPY_PASTE)
347     return atom_cache_.GetAtom(kClipboard);
348 
349   return XA_PRIMARY;
350 }
351 
LookupStorageForAtom(::Atom atom)352 const SelectionFormatMap& Clipboard::AuraX11Details::LookupStorageForAtom(
353     ::Atom atom) {
354   if (atom == XA_PRIMARY)
355     return primary_owner_.selection_format_map();
356 
357   DCHECK_EQ(atom_cache_.GetAtom(kClipboard), atom);
358   return clipboard_owner_.selection_format_map();
359 }
360 
361 ui::SelectionRequestor*
GetSelectionRequestorForClipboardType(ClipboardType type)362 Clipboard::AuraX11Details::GetSelectionRequestorForClipboardType(
363     ClipboardType type) {
364   if (type == CLIPBOARD_TYPE_COPY_PASTE)
365     return &clipboard_requestor_;
366   else
367     return &primary_requestor_;
368 }
369 
CreateNewClipboardData()370 void Clipboard::AuraX11Details::CreateNewClipboardData() {
371   clipboard_data_ = SelectionFormatMap();
372 }
373 
InsertMapping(const std::string & key,const scoped_refptr<base::RefCountedMemory> & memory)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);
379 }
380 
TakeOwnershipOfSelection(ClipboardType type)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_);
386 }
387 
RequestAndWaitForTypes(ClipboardType type,const std::vector<::Atom> & types)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);
396 
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);
402     }
403   } else {
404     TargetList targets = WaitAndGetTargetsList(type);
405     SelectionRequestor* receiver = GetSelectionRequestorForClipboardType(type);
406 
407     std::vector< ::Atom> intersection;
408     ui::GetAtomIntersection(types, targets.target_list(), &intersection);
409     return receiver->RequestAndWaitForTypes(intersection);
410   }
411 
412   return SelectionData();
413 }
414 
WaitAndGetTargetsList(ClipboardType type)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);
422 
423     for (SelectionFormatMap::const_iterator it = format_map.begin();
424          it != format_map.end(); ++it) {
425       out.push_back(it->first);
426     }
427   } else {
428     scoped_refptr<base::RefCountedMemory> data;
429     size_t out_data_items = 0;
430     ::Atom out_type = None;
431 
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);
459         }
460       }
461     }
462   }
463 
464   return TargetList(out, &atom_cache_);
465 }
466 
GetTextAtoms() const467 std::vector< ::Atom> Clipboard::AuraX11Details::GetTextAtoms() const {
468   return GetTextAtomsFrom(&atom_cache_);
469 }
470 
GetAtomsForFormat(const Clipboard::FormatType & format)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;
476 }
477 
Clear(ClipboardType type)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();
483 }
484 
Dispatch(const base::NativeEvent & event)485 bool Clipboard::AuraX11Details::Dispatch(const base::NativeEvent& event) {
486   XEvent* xev = event;
487 
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;
495     }
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;
502     }
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;
509     }
510     default:
511       break;
512   }
513 
514   return true;
515 }
516 
517 ///////////////////////////////////////////////////////////////////////////////
518 // Clipboard
519 
Clipboard()520 Clipboard::Clipboard()
521     : aurax11_details_(new AuraX11Details) {
522   DCHECK(CalledOnValidThread());
523 }
524 
~Clipboard()525 Clipboard::~Clipboard() {
526   DCHECK(CalledOnValidThread());
527 
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.
531 }
532 
WriteObjects(ClipboardType type,const ObjectMap & objects)533 void Clipboard::WriteObjects(ClipboardType type, const ObjectMap& objects) {
534   DCHECK(CalledOnValidThread());
535   DCHECK(IsSupportedClipboardType(type));
536 
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);
541   }
542   aurax11_details_->TakeOwnershipOfSelection(type);
543 
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);
551     }
552   }
553 }
554 
IsFormatAvailable(const FormatType & format,ClipboardType type) const555 bool Clipboard::IsFormatAvailable(const FormatType& format,
556                                   ClipboardType type) const {
557   DCHECK(CalledOnValidThread());
558   DCHECK(IsSupportedClipboardType(type));
559 
560   TargetList target_list = aurax11_details_->WaitAndGetTargetsList(type);
561   return target_list.ContainsFormat(format);
562 }
563 
Clear(ClipboardType type)564 void Clipboard::Clear(ClipboardType type) {
565   DCHECK(CalledOnValidThread());
566   DCHECK(IsSupportedClipboardType(type));
567   aurax11_details_->Clear(type);
568 }
569 
ReadAvailableTypes(ClipboardType type,std::vector<string16> * types,bool * contains_filenames) const570 void Clipboard::ReadAvailableTypes(ClipboardType type,
571                                    std::vector<string16>* types,
572                                    bool* contains_filenames) const {
573   DCHECK(CalledOnValidThread());
574   if (!types || !contains_filenames) {
575     NOTREACHED();
576     return;
577   }
578 
579   TargetList target_list = aurax11_details_->WaitAndGetTargetsList(type);
580 
581   types->clear();
582 
583   if (target_list.ContainsText())
584     types->push_back(UTF8ToUTF16(kMimeTypeText));
585   if (target_list.ContainsFormat(GetHtmlFormatType()))
586     types->push_back(UTF8ToUTF16(kMimeTypeHTML));
587   if (target_list.ContainsFormat(GetRtfFormatType()))
588     types->push_back(UTF8ToUTF16(kMimeTypeRTF));
589   if (target_list.ContainsFormat(GetBitmapFormatType()))
590     types->push_back(UTF8ToUTF16(kMimeTypePNG));
591   *contains_filenames = false;
592 
593   SelectionData data(aurax11_details_->RequestAndWaitForTypes(
594       type, aurax11_details_->GetAtomsForFormat(GetWebCustomDataFormatType())));
595   if (data.IsValid())
596     ReadCustomDataTypes(data.GetData(), data.GetSize(), types);
597 }
598 
ReadText(ClipboardType type,string16 * result) const599 void Clipboard::ReadText(ClipboardType type, string16* result) const {
600   DCHECK(CalledOnValidThread());
601 
602   SelectionData data(aurax11_details_->RequestAndWaitForTypes(
603       type, aurax11_details_->GetTextAtoms()));
604   if (data.IsValid()) {
605     std::string text = data.GetText();
606     *result = UTF8ToUTF16(text);
607   }
608 }
609 
ReadAsciiText(ClipboardType type,std::string * result) const610 void Clipboard::ReadAsciiText(ClipboardType type, std::string* result) const {
611   DCHECK(CalledOnValidThread());
612 
613   SelectionData data(aurax11_details_->RequestAndWaitForTypes(
614       type, aurax11_details_->GetTextAtoms()));
615   if (data.IsValid())
616     result->assign(data.GetText());
617 }
618 
619 // TODO(estade): handle different charsets.
620 // TODO(port): set *src_url.
ReadHTML(ClipboardType type,string16 * markup,std::string * src_url,uint32 * fragment_start,uint32 * fragment_end) const621 void Clipboard::ReadHTML(ClipboardType type,
622                          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;
632 
633   SelectionData data(aurax11_details_->RequestAndWaitForTypes(
634       type, aurax11_details_->GetAtomsForFormat(GetHtmlFormatType())));
635   if (data.IsValid()) {
636     *markup = data.GetHtml();
637 
638     *fragment_start = 0;
639     DCHECK(markup->length() <= kuint32max);
640     *fragment_end = static_cast<uint32>(markup->length());
641   }
642 }
643 
ReadRTF(ClipboardType type,std::string * result) const644 void Clipboard::ReadRTF(ClipboardType type, std::string* result) const {
645   DCHECK(CalledOnValidThread());
646 
647   SelectionData data(aurax11_details_->RequestAndWaitForTypes(
648       type, aurax11_details_->GetAtomsForFormat(GetRtfFormatType())));
649   if (data.IsValid())
650     data.AssignTo(result);
651 }
652 
ReadImage(ClipboardType type) const653 SkBitmap Clipboard::ReadImage(ClipboardType type) const {
654   DCHECK(CalledOnValidThread());
655 
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);
662   }
663 
664   return SkBitmap();
665 }
666 
ReadCustomData(ClipboardType clipboard_type,const string16 & type,string16 * result) const667 void Clipboard::ReadCustomData(ClipboardType clipboard_type,
668                                const string16& type,
669                                string16* result) const {
670   DCHECK(CalledOnValidThread());
671 
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);
677 }
678 
ReadBookmark(string16 * title,std::string * url) const679 void Clipboard::ReadBookmark(string16* title, std::string* url) const {
680   DCHECK(CalledOnValidThread());
681   // TODO(erg): This was left NOTIMPLEMENTED() in the gtk port too.
682   NOTIMPLEMENTED();
683 }
684 
ReadData(const FormatType & format,std::string * result) const685 void Clipboard::ReadData(const FormatType& format, std::string* result) const {
686   DCHECK(CalledOnValidThread());
687 
688   SelectionData data(aurax11_details_->RequestAndWaitForTypes(
689       CLIPBOARD_TYPE_COPY_PASTE, aurax11_details_->GetAtomsForFormat(format)));
690   if (data.IsValid())
691     data.AssignTo(result);
692 }
693 
GetSequenceNumber(ClipboardType type)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();
700 }
701 
WriteText(const char * text_data,size_t text_len)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));
706 
707   aurax11_details_->InsertMapping(kMimeTypeText, mem);
708   aurax11_details_->InsertMapping(kText, mem);
709   aurax11_details_->InsertMapping(kString, mem);
710   aurax11_details_->InsertMapping(kUtf8String, mem);
711 }
712 
WriteHTML(const char * markup_data,size_t markup_len,const char * url_data,size_t url_len)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';
724 
725   scoped_refptr<base::RefCountedMemory> mem(
726       base::RefCountedString::TakeString(&data));
727   aurax11_details_->InsertMapping(kMimeTypeHTML, mem);
728 }
729 
WriteRTF(const char * rtf_data,size_t data_len)730 void Clipboard::WriteRTF(const char* rtf_data, size_t data_len) {
731   WriteData(GetRtfFormatType(), rtf_data, data_len);
732 }
733 
WriteBookmark(const char * title_data,size_t title_len,const char * url_data,size_t url_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   string16 url = UTF8ToUTF16(std::string(url_data, url_len) + "\n");
740   string16 title = UTF8ToUTF16(std::string(title_data, title_len));
741 
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));
747 
748   aurax11_details_->InsertMapping(kMimeTypeMozillaURL, mem);
749 }
750 
751 // Write an extra flavor that signifies WebKit was the last to modify the
752 // pasteboard. This flavor has no data.
WriteWebSmartPaste()753 void Clipboard::WriteWebSmartPaste() {
754   aurax11_details_->InsertMapping(kMimeTypeWebkitSmartPaste,
755                                   scoped_refptr<base::RefCountedMemory>());
756 }
757 
WriteBitmap(const SkBitmap & bitmap)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));
765   }
766 }
767 
WriteData(const FormatType & format,const char * data_data,size_t data_len)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;
775 
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);
780 }
781 
782 // static
GetFormatType(const std::string & format_string)783 Clipboard::FormatType Clipboard::GetFormatType(
784     const std::string& format_string) {
785   return FormatType::Deserialize(format_string);
786 }
787 
788 // static
GetUrlFormatType()789 const Clipboard::FormatType& Clipboard::GetUrlFormatType() {
790   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeURIList));
791   return type;
792 }
793 
794 // static
GetUrlWFormatType()795 const Clipboard::FormatType& Clipboard::GetUrlWFormatType() {
796   return GetUrlFormatType();
797 }
798 
799 // static
GetPlainTextFormatType()800 const Clipboard::FormatType& Clipboard::GetPlainTextFormatType() {
801   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeText));
802   return type;
803 }
804 
805 // static
GetPlainTextWFormatType()806 const Clipboard::FormatType& Clipboard::GetPlainTextWFormatType() {
807   return GetPlainTextFormatType();
808 }
809 
810 // static
GetFilenameFormatType()811 const Clipboard::FormatType& Clipboard::GetFilenameFormatType() {
812   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeFilename));
813   return type;
814 }
815 
816 // static
GetFilenameWFormatType()817 const Clipboard::FormatType& Clipboard::GetFilenameWFormatType() {
818   return Clipboard::GetFilenameFormatType();
819 }
820 
821 // static
GetHtmlFormatType()822 const Clipboard::FormatType& Clipboard::GetHtmlFormatType() {
823   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeHTML));
824   return type;
825 }
826 
827 // static
GetRtfFormatType()828 const Clipboard::FormatType& Clipboard::GetRtfFormatType() {
829   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeRTF));
830   return type;
831 }
832 
833 // static
GetBitmapFormatType()834 const Clipboard::FormatType& Clipboard::GetBitmapFormatType() {
835   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypePNG));
836   return type;
837 }
838 
839 // static
GetWebKitSmartPasteFormatType()840 const Clipboard::FormatType& Clipboard::GetWebKitSmartPasteFormatType() {
841   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeWebkitSmartPaste));
842   return type;
843 }
844 
845 // static
GetWebCustomDataFormatType()846 const Clipboard::FormatType& Clipboard::GetWebCustomDataFormatType() {
847   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeWebCustomData));
848   return type;
849 }
850 
851 // static
GetPepperCustomDataFormatType()852 const Clipboard::FormatType& Clipboard::GetPepperCustomDataFormatType() {
853   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypePepperCustomData));
854   return type;
855 }
856 
857 }  // namespace ui
858