Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / ui / base / clipboard / clipboard_aurax11.cc
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/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"
33
34 namespace ui {
35
36 namespace {
37
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";
45
46 const char* kAtomsToCache[] = {
47   kClipboard,
48   kClipboardManager,
49   Clipboard::kMimeTypePNG,
50   kMimeTypeFilename,
51   kMimeTypeMozillaURL,
52   kMimeTypeWebkitSmartPaste,
53   kSaveTargets,
54   kString,
55   kTargets,
56   kText,
57   kUtf8String,
58   NULL
59 };
60
61 ///////////////////////////////////////////////////////////////////////////////
62
63 // Uses the XFixes API to provide sequence numbers for GetSequenceNumber().
64 class SelectionChangeObserver : public ui::PlatformEventObserver {
65  public:
66   static SelectionChangeObserver* GetInstance();
67
68   uint64 clipboard_sequence_number() const {
69     return clipboard_sequence_number_;
70   }
71   uint64 primary_sequence_number() const { return primary_sequence_number_; }
72
73  private:
74   friend struct DefaultSingletonTraits<SelectionChangeObserver>;
75
76   SelectionChangeObserver();
77   virtual ~SelectionChangeObserver();
78
79   // ui::PlatformEventObserver:
80   virtual void WillProcessEvent(const ui::PlatformEvent& event) OVERRIDE;
81   virtual void DidProcessEvent(const ui::PlatformEvent& event) OVERRIDE {}
82
83   int event_base_;
84   Atom clipboard_atom_;
85   uint64 clipboard_sequence_number_;
86   uint64 primary_sequence_number_;
87
88   DISALLOW_COPY_AND_ASSIGN(SelectionChangeObserver);
89 };
90
91 SelectionChangeObserver::SelectionChangeObserver()
92     : event_base_(-1),
93       clipboard_atom_(None),
94       clipboard_sequence_number_(0),
95       primary_sequence_number_(0) {
96   int ignored;
97   if (XFixesQueryExtension(gfx::GetXDisplay(), &event_base_, &ignored)) {
98     clipboard_atom_ = XInternAtom(gfx::GetXDisplay(), kClipboard, false);
99     XFixesSelectSelectionInput(gfx::GetXDisplay(), GetX11RootWindow(),
100                                clipboard_atom_,
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(),
108                                XA_PRIMARY,
109                                XFixesSetSelectionOwnerNotifyMask |
110                                XFixesSelectionWindowDestroyNotifyMask |
111                                XFixesSelectionClientCloseNotifyMask);
112
113     ui::PlatformEventSource::GetInstance()->AddPlatformEventObserver(this);
114   }
115 }
116
117 SelectionChangeObserver::~SelectionChangeObserver() {
118   // We are a singleton; we will outlive the event source.
119 }
120
121 SelectionChangeObserver* SelectionChangeObserver::GetInstance() {
122   return Singleton<SelectionChangeObserver>::get();
123 }
124
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_++;
133     } else {
134       DLOG(ERROR) << "Unexpected selection atom: " << ev->selection;
135     }
136   }
137 }
138
139 ///////////////////////////////////////////////////////////////////////////////
140
141 // Represents a list of possible return types. Copy constructable.
142 class TargetList {
143  public:
144   typedef std::vector< ::Atom> AtomVector;
145
146   TargetList(const AtomVector& target_list, X11AtomCache* atom_cache);
147
148   const AtomVector& target_list() { return target_list_; }
149
150   bool ContainsText() const;
151   bool ContainsFormat(const Clipboard::FormatType& format_type) const;
152   bool ContainsAtom(::Atom atom) const;
153
154  private:
155   AtomVector target_list_;
156   X11AtomCache* atom_cache_;
157 };
158
159 TargetList::TargetList(const AtomVector& target_list,
160                        X11AtomCache* atom_cache)
161     : target_list_(target_list),
162       atom_cache_(atom_cache) {
163 }
164
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))
170       return true;
171   }
172
173   return false;
174 }
175
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);
180 }
181
182 bool TargetList::ContainsAtom(::Atom atom) const {
183   return find(target_list_.begin(), target_list_.end(), atom)
184       != target_list_.end();
185 }
186
187 }  // namespace
188
189 ///////////////////////////////////////////////////////////////////////////////
190
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.
195
196 Clipboard::FormatType::FormatType() {
197 }
198
199 Clipboard::FormatType::FormatType(const std::string& native_format)
200     : data_(native_format) {
201 }
202
203 Clipboard::FormatType::~FormatType() {
204 }
205
206 std::string Clipboard::FormatType::Serialize() const {
207   return data_;
208 }
209
210 // static
211 Clipboard::FormatType Clipboard::FormatType::Deserialize(
212     const std::string& serialization) {
213   return FormatType(serialization);
214 }
215
216 bool Clipboard::FormatType::operator<(const FormatType& other) const {
217   return data_ < other.data_;
218 }
219
220 bool Clipboard::FormatType::Equals(const FormatType& other) const {
221   return data_ == other.data_;
222 }
223
224 ///////////////////////////////////////////////////////////////////////////////
225 // Clipboard::AuraX11Details
226
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 {
230  public:
231   AuraX11Details();
232   virtual ~AuraX11Details();
233
234   X11AtomCache* atom_cache() { return &atom_cache_; }
235
236   // Returns the X11 type that we pass to various XSelection functions for the
237   // given type.
238   ::Atom LookupSelectionForClipboardType(ClipboardType type) const;
239
240   // Returns the X11 type that we pass to various XSelection functions for
241   // CLIPBOARD_TYPE_COPY_PASTE.
242   ::Atom GetCopyPasteSelection() const;
243
244   // Finds the SelectionFormatMap for the incoming selection atom.
245   const SelectionFormatMap& LookupStorageForAtom(::Atom atom);
246
247   // As we need to collect all the data types before we tell X11 that we own a
248   // particular selection, we create a temporary clipboard mapping that
249   // InsertMapping writes to. Then we commit it in TakeOwnershipOfSelection,
250   // where we save it in one of the clipboard data slots.
251   void CreateNewClipboardData();
252
253   // Inserts a mapping into clipboard_data_.
254   void InsertMapping(const std::string& key,
255                      const scoped_refptr<base::RefCountedMemory>& memory);
256
257   // Moves the temporary |clipboard_data_| to the long term data storage for
258   // |type|.
259   void TakeOwnershipOfSelection(ClipboardType type);
260
261   // Returns the first of |types| offered by the current selection holder in
262   // |data_out|, or returns NULL if none of those types are available.
263   //
264   // If the selection holder is us, this call is synchronous and we pull
265   // the data out of |clipboard_selection_| or |primary_selection_|. If the
266   // selection holder is some other window, we spin up a nested message loop
267   // and do the asynchronous dance with whatever application is holding the
268   // selection.
269   ui::SelectionData RequestAndWaitForTypes(ClipboardType type,
270                                            const std::vector< ::Atom>& types);
271
272   // Retrieves the list of possible data types the current clipboard owner has.
273   //
274   // If the selection holder is us, this is synchronous, otherwise this runs a
275   // blocking message loop.
276   TargetList WaitAndGetTargetsList(ClipboardType type);
277
278   // Returns a list of all text atoms that we handle.
279   std::vector< ::Atom> GetTextAtoms() const;
280
281   // Returns a vector with a |format| converted to an X11 atom.
282   std::vector< ::Atom> GetAtomsForFormat(const Clipboard::FormatType& format);
283
284   // Clears a certain clipboard type, whether we own it or not.
285   void Clear(ClipboardType type);
286
287   // If we own the CLIPBOARD selection, requests the clipboard manager to take
288   // ownership of it.
289   void StoreCopyPasteDataAndWait();
290
291  private:
292   // PlatformEventDispatcher:
293   virtual bool CanDispatchEvent(const PlatformEvent& event) OVERRIDE;
294   virtual uint32_t DispatchEvent(const PlatformEvent& event) OVERRIDE;
295
296   // Our X11 state.
297   Display* x_display_;
298   ::Window x_root_window_;
299
300   // Input-only window used as a selection owner.
301   ::Window x_window_;
302
303   X11AtomCache atom_cache_;
304
305   // Object which requests and receives selection data.
306   SelectionRequestor selection_requestor_;
307
308   // Temporary target map that we write to during DispatchObects.
309   SelectionFormatMap clipboard_data_;
310
311   // Objects which offer selection data to other windows.
312   SelectionOwner clipboard_owner_;
313   SelectionOwner primary_owner_;
314
315   DISALLOW_COPY_AND_ASSIGN(AuraX11Details);
316 };
317
318 Clipboard::AuraX11Details::AuraX11Details()
319     : x_display_(gfx::GetXDisplay()),
320       x_root_window_(DefaultRootWindow(x_display_)),
321       x_window_(XCreateWindow(
322           x_display_, x_root_window_,
323           -100, -100, 10, 10,  // x, y, width, height
324           0,                   // border width
325           CopyFromParent,      // depth
326           InputOnly,
327           CopyFromParent,      // visual
328           0,
329           NULL)),
330       atom_cache_(x_display_, kAtomsToCache),
331       selection_requestor_(x_display_, x_window_, this),
332       clipboard_owner_(x_display_, x_window_, atom_cache_.GetAtom(kClipboard)),
333       primary_owner_(x_display_, x_window_, XA_PRIMARY) {
334   // We don't know all possible MIME types at compile time.
335   atom_cache_.allow_uncached_atoms();
336
337   XStoreName(x_display_, x_window_, "Chromium clipboard");
338   XSelectInput(x_display_, x_window_, PropertyChangeMask);
339
340   if (PlatformEventSource::GetInstance())
341     PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this);
342 }
343
344 Clipboard::AuraX11Details::~AuraX11Details() {
345   if (PlatformEventSource::GetInstance())
346     PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this);
347
348   XDestroyWindow(x_display_, x_window_);
349 }
350
351 ::Atom Clipboard::AuraX11Details::LookupSelectionForClipboardType(
352     ClipboardType type) const {
353   if (type == CLIPBOARD_TYPE_COPY_PASTE)
354     return GetCopyPasteSelection();
355
356   return XA_PRIMARY;
357 }
358
359 ::Atom Clipboard::AuraX11Details::GetCopyPasteSelection() const {
360   return atom_cache_.GetAtom(kClipboard);
361 }
362
363 const SelectionFormatMap& Clipboard::AuraX11Details::LookupStorageForAtom(
364     ::Atom atom) {
365   if (atom == XA_PRIMARY)
366     return primary_owner_.selection_format_map();
367
368   DCHECK_EQ(GetCopyPasteSelection(), atom);
369   return clipboard_owner_.selection_format_map();
370 }
371
372 void Clipboard::AuraX11Details::CreateNewClipboardData() {
373   clipboard_data_ = SelectionFormatMap();
374 }
375
376 void Clipboard::AuraX11Details::InsertMapping(
377     const std::string& key,
378     const scoped_refptr<base::RefCountedMemory>& memory) {
379   ::Atom atom_key = atom_cache_.GetAtom(key.c_str());
380   clipboard_data_.Insert(atom_key, memory);
381 }
382
383 void Clipboard::AuraX11Details::TakeOwnershipOfSelection(ClipboardType type) {
384   if (type == CLIPBOARD_TYPE_COPY_PASTE)
385     return clipboard_owner_.TakeOwnershipOfSelection(clipboard_data_);
386   else
387     return primary_owner_.TakeOwnershipOfSelection(clipboard_data_);
388 }
389
390 SelectionData Clipboard::AuraX11Details::RequestAndWaitForTypes(
391     ClipboardType type,
392     const std::vector< ::Atom>& types) {
393   ::Atom selection_name = LookupSelectionForClipboardType(type);
394   if (XGetSelectionOwner(x_display_, selection_name) == x_window_) {
395     // We can local fastpath instead of playing the nested message loop game
396     // with the X server.
397     const SelectionFormatMap& format_map = LookupStorageForAtom(selection_name);
398
399     for (std::vector< ::Atom>::const_iterator it = types.begin();
400          it != types.end(); ++it) {
401       SelectionFormatMap::const_iterator format_map_it = format_map.find(*it);
402       if (format_map_it != format_map.end())
403         return SelectionData(format_map_it->first, format_map_it->second);
404     }
405   } else {
406     TargetList targets = WaitAndGetTargetsList(type);
407
408     ::Atom selection_name = LookupSelectionForClipboardType(type);
409     std::vector< ::Atom> intersection;
410     ui::GetAtomIntersection(types, targets.target_list(), &intersection);
411     return selection_requestor_.RequestAndWaitForTypes(selection_name,
412                                                        intersection);
413   }
414
415   return SelectionData();
416 }
417
418 TargetList Clipboard::AuraX11Details::WaitAndGetTargetsList(
419     ClipboardType type) {
420   ::Atom selection_name = LookupSelectionForClipboardType(type);
421   std::vector< ::Atom> out;
422   if (XGetSelectionOwner(x_display_, selection_name) == x_window_) {
423     // We can local fastpath and return the list of local targets.
424     const SelectionFormatMap& format_map = LookupStorageForAtom(selection_name);
425
426     for (SelectionFormatMap::const_iterator it = format_map.begin();
427          it != format_map.end(); ++it) {
428       out.push_back(it->first);
429     }
430   } else {
431     scoped_refptr<base::RefCountedMemory> data;
432     size_t out_data_items = 0;
433     ::Atom out_type = None;
434
435     if (selection_requestor_.PerformBlockingConvertSelection(
436             selection_name,
437             atom_cache_.GetAtom(kTargets),
438             &data,
439             &out_data_items,
440             &out_type)) {
441       // Some apps return an |out_type| of "TARGETS". (crbug.com/377893)
442       if (out_type == XA_ATOM || out_type == atom_cache_.GetAtom(kTargets)) {
443         const ::Atom* atom_array =
444             reinterpret_cast<const ::Atom*>(data->front());
445         for (size_t i = 0; i < out_data_items; ++i)
446           out.push_back(atom_array[i]);
447       }
448     } else {
449       // There was no target list. Most Java apps doesn't offer a TARGETS list,
450       // even though they AWT to. They will offer individual text types if you
451       // ask. If this is the case we attempt to make sense of the contents as
452       // text. This is pretty unfortunate since it means we have to actually
453       // copy the data to see if it is available, but at least this path
454       // shouldn't be hit for conforming programs.
455       std::vector< ::Atom> types = GetTextAtoms();
456       for (std::vector< ::Atom>::const_iterator it = types.begin();
457            it != types.end(); ++it) {
458         ::Atom type = None;
459         if (selection_requestor_.PerformBlockingConvertSelection(selection_name,
460                                                                  *it,
461                                                                  NULL,
462                                                                  NULL,
463                                                                  &type) &&
464             type == *it) {
465           out.push_back(*it);
466         }
467       }
468     }
469   }
470
471   return TargetList(out, &atom_cache_);
472 }
473
474 std::vector< ::Atom> Clipboard::AuraX11Details::GetTextAtoms() const {
475   return GetTextAtomsFrom(&atom_cache_);
476 }
477
478 std::vector< ::Atom> Clipboard::AuraX11Details::GetAtomsForFormat(
479     const Clipboard::FormatType& format) {
480   std::vector< ::Atom> atoms;
481   atoms.push_back(atom_cache_.GetAtom(format.ToString().c_str()));
482   return atoms;
483 }
484
485 void Clipboard::AuraX11Details::Clear(ClipboardType type) {
486   if (type == CLIPBOARD_TYPE_COPY_PASTE)
487     clipboard_owner_.ClearSelectionOwner();
488   else
489     primary_owner_.ClearSelectionOwner();
490 }
491
492 void Clipboard::AuraX11Details::StoreCopyPasteDataAndWait() {
493   ::Atom selection = GetCopyPasteSelection();
494   if (XGetSelectionOwner(x_display_, selection) != x_window_)
495     return;
496
497   ::Atom clipboard_manager_atom = atom_cache_.GetAtom(kClipboardManager);
498   if (XGetSelectionOwner(x_display_, clipboard_manager_atom) == None)
499     return;
500
501   const SelectionFormatMap& format_map = LookupStorageForAtom(selection);
502   if (format_map.size() == 0)
503     return;
504   std::vector<Atom> targets = format_map.GetTypes();
505
506   base::TimeTicks start = base::TimeTicks::Now();
507   selection_requestor_.PerformBlockingConvertSelectionWithParameter(
508       atom_cache_.GetAtom(kClipboardManager),
509       atom_cache_.GetAtom(kSaveTargets),
510       targets);
511   UMA_HISTOGRAM_TIMES("Clipboard.X11StoreCopyPasteDuration",
512                       base::TimeTicks::Now() - start);
513 }
514
515 bool Clipboard::AuraX11Details::CanDispatchEvent(const PlatformEvent& event) {
516   if (event->xany.window == x_window_)
517     return true;
518
519   if (event->type == PropertyNotify) {
520     return primary_owner_.CanDispatchPropertyEvent(*event) ||
521         clipboard_owner_.CanDispatchPropertyEvent(*event) ||
522         selection_requestor_.CanDispatchPropertyEvent(*event);
523   }
524   return false;
525 }
526
527 uint32_t Clipboard::AuraX11Details::DispatchEvent(const PlatformEvent& xev) {
528   switch (xev->type) {
529     case SelectionRequest: {
530       if (xev->xselectionrequest.selection == XA_PRIMARY) {
531         primary_owner_.OnSelectionRequest(*xev);
532       } else {
533         // We should not get requests for the CLIPBOARD_MANAGER selection
534         // because we never take ownership of it.
535         DCHECK_EQ(GetCopyPasteSelection(), xev->xselectionrequest.selection);
536         clipboard_owner_.OnSelectionRequest(*xev);
537       }
538       break;
539     }
540     case SelectionNotify: {
541       selection_requestor_.OnSelectionNotify(*xev);
542       break;
543     }
544     case SelectionClear: {
545       if (xev->xselectionclear.selection == XA_PRIMARY) {
546         primary_owner_.OnSelectionClear(*xev);
547       } else {
548         // We should not get requests for the CLIPBOARD_MANAGER selection
549         // because we never take ownership of it.
550         DCHECK_EQ(GetCopyPasteSelection(), xev->xselection.selection);
551         clipboard_owner_.OnSelectionClear(*xev);
552         }
553       break;
554     }
555     case PropertyNotify: {
556       if (primary_owner_.CanDispatchPropertyEvent(*xev))
557         primary_owner_.OnPropertyEvent(*xev);
558       if (clipboard_owner_.CanDispatchPropertyEvent(*xev))
559         clipboard_owner_.OnPropertyEvent(*xev);
560       if (selection_requestor_.CanDispatchPropertyEvent(*xev))
561         selection_requestor_.OnPropertyEvent(*xev);
562       break;
563     }
564     default:
565       break;
566   }
567
568   return POST_DISPATCH_NONE;
569 }
570
571 ///////////////////////////////////////////////////////////////////////////////
572 // Clipboard
573
574 Clipboard::Clipboard()
575     : aurax11_details_(new AuraX11Details) {
576   DCHECK(CalledOnValidThread());
577 }
578
579 Clipboard::~Clipboard() {
580   DCHECK(CalledOnValidThread());
581
582   aurax11_details_->StoreCopyPasteDataAndWait();
583 }
584
585 void Clipboard::WriteObjects(ClipboardType type, const ObjectMap& objects) {
586   DCHECK(CalledOnValidThread());
587   DCHECK(IsSupportedClipboardType(type));
588
589   aurax11_details_->CreateNewClipboardData();
590   for (ObjectMap::const_iterator iter = objects.begin();
591        iter != objects.end(); ++iter) {
592     DispatchObject(static_cast<ObjectType>(iter->first), iter->second);
593   }
594   aurax11_details_->TakeOwnershipOfSelection(type);
595
596   if (type == CLIPBOARD_TYPE_COPY_PASTE) {
597     ObjectMap::const_iterator text_iter = objects.find(CBF_TEXT);
598     if (text_iter != objects.end()) {
599       aurax11_details_->CreateNewClipboardData();
600       const ObjectMapParams& params_vector = text_iter->second;
601       if (params_vector.size()) {
602         const ObjectMapParam& char_vector = params_vector[0];
603         if (char_vector.size())
604           WriteText(&char_vector.front(), char_vector.size());
605       }
606       aurax11_details_->TakeOwnershipOfSelection(CLIPBOARD_TYPE_SELECTION);
607     }
608   }
609 }
610
611 bool Clipboard::IsFormatAvailable(const FormatType& format,
612                                   ClipboardType type) const {
613   DCHECK(CalledOnValidThread());
614   DCHECK(IsSupportedClipboardType(type));
615
616   TargetList target_list = aurax11_details_->WaitAndGetTargetsList(type);
617   if (format.Equals(GetPlainTextFormatType()) ||
618       format.Equals(GetUrlFormatType())) {
619     return target_list.ContainsText();
620   }
621   return target_list.ContainsFormat(format);
622 }
623
624 void Clipboard::Clear(ClipboardType type) {
625   DCHECK(CalledOnValidThread());
626   DCHECK(IsSupportedClipboardType(type));
627   aurax11_details_->Clear(type);
628 }
629
630 void Clipboard::ReadAvailableTypes(ClipboardType type,
631                                    std::vector<base::string16>* types,
632                                    bool* contains_filenames) const {
633   DCHECK(CalledOnValidThread());
634   if (!types || !contains_filenames) {
635     NOTREACHED();
636     return;
637   }
638
639   TargetList target_list = aurax11_details_->WaitAndGetTargetsList(type);
640
641   types->clear();
642
643   if (target_list.ContainsText())
644     types->push_back(base::UTF8ToUTF16(kMimeTypeText));
645   if (target_list.ContainsFormat(GetHtmlFormatType()))
646     types->push_back(base::UTF8ToUTF16(kMimeTypeHTML));
647   if (target_list.ContainsFormat(GetRtfFormatType()))
648     types->push_back(base::UTF8ToUTF16(kMimeTypeRTF));
649   if (target_list.ContainsFormat(GetBitmapFormatType()))
650     types->push_back(base::UTF8ToUTF16(kMimeTypePNG));
651   *contains_filenames = false;
652
653   SelectionData data(aurax11_details_->RequestAndWaitForTypes(
654       type, aurax11_details_->GetAtomsForFormat(GetWebCustomDataFormatType())));
655   if (data.IsValid())
656     ReadCustomDataTypes(data.GetData(), data.GetSize(), types);
657 }
658
659 void Clipboard::ReadText(ClipboardType type, base::string16* result) const {
660   DCHECK(CalledOnValidThread());
661
662   SelectionData data(aurax11_details_->RequestAndWaitForTypes(
663       type, aurax11_details_->GetTextAtoms()));
664   if (data.IsValid()) {
665     std::string text = data.GetText();
666     *result = base::UTF8ToUTF16(text);
667   }
668 }
669
670 void Clipboard::ReadAsciiText(ClipboardType type, std::string* result) const {
671   DCHECK(CalledOnValidThread());
672
673   SelectionData data(aurax11_details_->RequestAndWaitForTypes(
674       type, aurax11_details_->GetTextAtoms()));
675   if (data.IsValid())
676     result->assign(data.GetText());
677 }
678
679 // TODO(estade): handle different charsets.
680 // TODO(port): set *src_url.
681 void Clipboard::ReadHTML(ClipboardType type,
682                          base::string16* markup,
683                          std::string* src_url,
684                          uint32* fragment_start,
685                          uint32* fragment_end) const {
686   DCHECK(CalledOnValidThread());
687   markup->clear();
688   if (src_url)
689     src_url->clear();
690   *fragment_start = 0;
691   *fragment_end = 0;
692
693   SelectionData data(aurax11_details_->RequestAndWaitForTypes(
694       type, aurax11_details_->GetAtomsForFormat(GetHtmlFormatType())));
695   if (data.IsValid()) {
696     *markup = data.GetHtml();
697
698     *fragment_start = 0;
699     DCHECK(markup->length() <= kuint32max);
700     *fragment_end = static_cast<uint32>(markup->length());
701   }
702 }
703
704 void Clipboard::ReadRTF(ClipboardType type, std::string* result) const {
705   DCHECK(CalledOnValidThread());
706
707   SelectionData data(aurax11_details_->RequestAndWaitForTypes(
708       type, aurax11_details_->GetAtomsForFormat(GetRtfFormatType())));
709   if (data.IsValid())
710     data.AssignTo(result);
711 }
712
713 SkBitmap Clipboard::ReadImage(ClipboardType type) const {
714   DCHECK(CalledOnValidThread());
715
716   SelectionData data(aurax11_details_->RequestAndWaitForTypes(
717       type, aurax11_details_->GetAtomsForFormat(GetBitmapFormatType())));
718   if (data.IsValid()) {
719     SkBitmap bitmap;
720     if (gfx::PNGCodec::Decode(data.GetData(), data.GetSize(), &bitmap))
721       return SkBitmap(bitmap);
722   }
723
724   return SkBitmap();
725 }
726
727 void Clipboard::ReadCustomData(ClipboardType clipboard_type,
728                                const base::string16& type,
729                                base::string16* result) const {
730   DCHECK(CalledOnValidThread());
731
732   SelectionData data(aurax11_details_->RequestAndWaitForTypes(
733       clipboard_type,
734       aurax11_details_->GetAtomsForFormat(GetWebCustomDataFormatType())));
735   if (data.IsValid())
736     ReadCustomDataForType(data.GetData(), data.GetSize(), type, result);
737 }
738
739 void Clipboard::ReadBookmark(base::string16* title, std::string* url) const {
740   DCHECK(CalledOnValidThread());
741   // TODO(erg): This was left NOTIMPLEMENTED() in the gtk port too.
742   NOTIMPLEMENTED();
743 }
744
745 void Clipboard::ReadData(const FormatType& format, std::string* result) const {
746   DCHECK(CalledOnValidThread());
747
748   SelectionData data(aurax11_details_->RequestAndWaitForTypes(
749       CLIPBOARD_TYPE_COPY_PASTE, aurax11_details_->GetAtomsForFormat(format)));
750   if (data.IsValid())
751     data.AssignTo(result);
752 }
753
754 uint64 Clipboard::GetSequenceNumber(ClipboardType type) {
755   DCHECK(CalledOnValidThread());
756   if (type == CLIPBOARD_TYPE_COPY_PASTE)
757     return SelectionChangeObserver::GetInstance()->clipboard_sequence_number();
758   else
759     return SelectionChangeObserver::GetInstance()->primary_sequence_number();
760 }
761
762 void Clipboard::WriteText(const char* text_data, size_t text_len) {
763   std::string str(text_data, text_len);
764   scoped_refptr<base::RefCountedMemory> mem(
765       base::RefCountedString::TakeString(&str));
766
767   aurax11_details_->InsertMapping(kMimeTypeText, mem);
768   aurax11_details_->InsertMapping(kText, mem);
769   aurax11_details_->InsertMapping(kString, mem);
770   aurax11_details_->InsertMapping(kUtf8String, mem);
771 }
772
773 void Clipboard::WriteHTML(const char* markup_data,
774                           size_t markup_len,
775                           const char* url_data,
776                           size_t url_len) {
777   // TODO(estade): We need to expand relative links with |url_data|.
778   static const char* html_prefix = "<meta http-equiv=\"content-type\" "
779                                    "content=\"text/html; charset=utf-8\">";
780   std::string data = html_prefix;
781   data += std::string(markup_data, markup_len);
782   // Some programs expect NULL-terminated data. See http://crbug.com/42624
783   data += '\0';
784
785   scoped_refptr<base::RefCountedMemory> mem(
786       base::RefCountedString::TakeString(&data));
787   aurax11_details_->InsertMapping(kMimeTypeHTML, mem);
788 }
789
790 void Clipboard::WriteRTF(const char* rtf_data, size_t data_len) {
791   WriteData(GetRtfFormatType(), rtf_data, data_len);
792 }
793
794 void Clipboard::WriteBookmark(const char* title_data,
795                               size_t title_len,
796                               const char* url_data,
797                               size_t url_len) {
798   // Write as a mozilla url (UTF16: URL, newline, title).
799   base::string16 url = base::UTF8ToUTF16(std::string(url_data, url_len) + "\n");
800   base::string16 title = base::UTF8ToUTF16(std::string(title_data, title_len));
801
802   std::vector<unsigned char> data;
803   ui::AddString16ToVector(url, &data);
804   ui::AddString16ToVector(title, &data);
805   scoped_refptr<base::RefCountedMemory> mem(
806       base::RefCountedBytes::TakeVector(&data));
807
808   aurax11_details_->InsertMapping(kMimeTypeMozillaURL, mem);
809 }
810
811 // Write an extra flavor that signifies WebKit was the last to modify the
812 // pasteboard. This flavor has no data.
813 void Clipboard::WriteWebSmartPaste() {
814   std::string empty;
815   aurax11_details_->InsertMapping(
816       kMimeTypeWebkitSmartPaste,
817       scoped_refptr<base::RefCountedMemory>(
818           base::RefCountedString::TakeString(&empty)));
819 }
820
821 void Clipboard::WriteBitmap(const SkBitmap& bitmap) {
822   // Encode the bitmap as a PNG for transport.
823   std::vector<unsigned char> output;
824   if (gfx::PNGCodec::FastEncodeBGRASkBitmap(bitmap, false, &output)) {
825     aurax11_details_->InsertMapping(kMimeTypePNG,
826                                     base::RefCountedBytes::TakeVector(
827                                         &output));
828   }
829 }
830
831 void Clipboard::WriteData(const FormatType& format,
832                           const char* data_data,
833                           size_t data_len) {
834   // We assume that certain mapping types are only written by trusted code.
835   // Therefore we must upkeep their integrity.
836   if (format.Equals(GetBitmapFormatType()))
837     return;
838
839   std::vector<unsigned char> bytes(data_data, data_data + data_len);
840   scoped_refptr<base::RefCountedMemory> mem(
841       base::RefCountedBytes::TakeVector(&bytes));
842   aurax11_details_->InsertMapping(format.ToString(), mem);
843 }
844
845 // static
846 Clipboard::FormatType Clipboard::GetFormatType(
847     const std::string& format_string) {
848   return FormatType::Deserialize(format_string);
849 }
850
851 // static
852 const Clipboard::FormatType& Clipboard::GetUrlFormatType() {
853   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeURIList));
854   return type;
855 }
856
857 // static
858 const Clipboard::FormatType& Clipboard::GetUrlWFormatType() {
859   return GetUrlFormatType();
860 }
861
862 // static
863 const Clipboard::FormatType& Clipboard::GetPlainTextFormatType() {
864   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeText));
865   return type;
866 }
867
868 // static
869 const Clipboard::FormatType& Clipboard::GetPlainTextWFormatType() {
870   return GetPlainTextFormatType();
871 }
872
873 // static
874 const Clipboard::FormatType& Clipboard::GetFilenameFormatType() {
875   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeFilename));
876   return type;
877 }
878
879 // static
880 const Clipboard::FormatType& Clipboard::GetFilenameWFormatType() {
881   return Clipboard::GetFilenameFormatType();
882 }
883
884 // static
885 const Clipboard::FormatType& Clipboard::GetHtmlFormatType() {
886   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeHTML));
887   return type;
888 }
889
890 // static
891 const Clipboard::FormatType& Clipboard::GetRtfFormatType() {
892   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeRTF));
893   return type;
894 }
895
896 // static
897 const Clipboard::FormatType& Clipboard::GetBitmapFormatType() {
898   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypePNG));
899   return type;
900 }
901
902 // static
903 const Clipboard::FormatType& Clipboard::GetWebKitSmartPasteFormatType() {
904   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeWebkitSmartPaste));
905   return type;
906 }
907
908 // static
909 const Clipboard::FormatType& Clipboard::GetWebCustomDataFormatType() {
910   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeWebCustomData));
911   return type;
912 }
913
914 // static
915 const Clipboard::FormatType& Clipboard::GetPepperCustomDataFormatType() {
916   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypePepperCustomData));
917   return type;
918 }
919
920 }  // namespace ui