Update To 11.40.268.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_aurax11.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   ~SelectionChangeObserver() override;
78
79   // ui::PlatformEventObserver:
80   void WillProcessEvent(const ui::PlatformEvent& event) override;
81   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 // ClipboardAuraX11::AuraX11Details
226
227 // Private implementation of our X11 integration. Keeps X11 headers out of the
228 // majority of chrome, which break badly.
229 class ClipboardAuraX11::AuraX11Details : public PlatformEventDispatcher {
230  public:
231   AuraX11Details();
232   ~AuraX11Details() override;
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   bool CanDispatchEvent(const PlatformEvent& event) override;
294   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 ClipboardAuraX11::AuraX11Details::AuraX11Details()
319     : x_display_(gfx::GetXDisplay()),
320       x_root_window_(DefaultRootWindow(x_display_)),
321       x_window_(XCreateWindow(x_display_,
322                               x_root_window_,
323                               -100,
324                               -100,
325                               10,
326                               10,              // x, y, width, height
327                               0,               // border width
328                               CopyFromParent,  // depth
329                               InputOnly,
330                               CopyFromParent,  // visual
331                               0,
332                               NULL)),
333       atom_cache_(x_display_, kAtomsToCache),
334       selection_requestor_(x_display_, x_window_, this),
335       clipboard_owner_(x_display_, x_window_, atom_cache_.GetAtom(kClipboard)),
336       primary_owner_(x_display_, x_window_, XA_PRIMARY) {
337   // We don't know all possible MIME types at compile time.
338   atom_cache_.allow_uncached_atoms();
339
340   XStoreName(x_display_, x_window_, "Chromium clipboard");
341   XSelectInput(x_display_, x_window_, PropertyChangeMask);
342
343   if (PlatformEventSource::GetInstance())
344     PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this);
345 }
346
347 ClipboardAuraX11::AuraX11Details::~AuraX11Details() {
348   if (PlatformEventSource::GetInstance())
349     PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this);
350
351   XDestroyWindow(x_display_, x_window_);
352 }
353
354 ::Atom ClipboardAuraX11::AuraX11Details::LookupSelectionForClipboardType(
355     ClipboardType type) const {
356   if (type == CLIPBOARD_TYPE_COPY_PASTE)
357     return GetCopyPasteSelection();
358
359   return XA_PRIMARY;
360 }
361
362 ::Atom ClipboardAuraX11::AuraX11Details::GetCopyPasteSelection() const {
363   return atom_cache_.GetAtom(kClipboard);
364 }
365
366 const SelectionFormatMap&
367 ClipboardAuraX11::AuraX11Details::LookupStorageForAtom(::Atom atom) {
368   if (atom == XA_PRIMARY)
369     return primary_owner_.selection_format_map();
370
371   DCHECK_EQ(GetCopyPasteSelection(), atom);
372   return clipboard_owner_.selection_format_map();
373 }
374
375 void ClipboardAuraX11::AuraX11Details::CreateNewClipboardData() {
376   clipboard_data_ = SelectionFormatMap();
377 }
378
379 void ClipboardAuraX11::AuraX11Details::InsertMapping(
380     const std::string& key,
381     const scoped_refptr<base::RefCountedMemory>& memory) {
382   ::Atom atom_key = atom_cache_.GetAtom(key.c_str());
383   clipboard_data_.Insert(atom_key, memory);
384 }
385
386 void ClipboardAuraX11::AuraX11Details::TakeOwnershipOfSelection(
387     ClipboardType type) {
388   if (type == CLIPBOARD_TYPE_COPY_PASTE)
389     return clipboard_owner_.TakeOwnershipOfSelection(clipboard_data_);
390   else
391     return primary_owner_.TakeOwnershipOfSelection(clipboard_data_);
392 }
393
394 SelectionData ClipboardAuraX11::AuraX11Details::RequestAndWaitForTypes(
395     ClipboardType type,
396     const std::vector<::Atom>& types) {
397   ::Atom selection_name = LookupSelectionForClipboardType(type);
398   if (XGetSelectionOwner(x_display_, selection_name) == x_window_) {
399     // We can local fastpath instead of playing the nested message loop game
400     // with the X server.
401     const SelectionFormatMap& format_map = LookupStorageForAtom(selection_name);
402
403     for (std::vector< ::Atom>::const_iterator it = types.begin();
404          it != types.end(); ++it) {
405       SelectionFormatMap::const_iterator format_map_it = format_map.find(*it);
406       if (format_map_it != format_map.end())
407         return SelectionData(format_map_it->first, format_map_it->second);
408     }
409   } else {
410     TargetList targets = WaitAndGetTargetsList(type);
411
412     ::Atom selection_name = LookupSelectionForClipboardType(type);
413     std::vector< ::Atom> intersection;
414     ui::GetAtomIntersection(types, targets.target_list(), &intersection);
415     return selection_requestor_.RequestAndWaitForTypes(selection_name,
416                                                        intersection);
417   }
418
419   return SelectionData();
420 }
421
422 TargetList ClipboardAuraX11::AuraX11Details::WaitAndGetTargetsList(
423     ClipboardType type) {
424   ::Atom selection_name = LookupSelectionForClipboardType(type);
425   std::vector< ::Atom> out;
426   if (XGetSelectionOwner(x_display_, selection_name) == x_window_) {
427     // We can local fastpath and return the list of local targets.
428     const SelectionFormatMap& format_map = LookupStorageForAtom(selection_name);
429
430     for (SelectionFormatMap::const_iterator it = format_map.begin();
431          it != format_map.end(); ++it) {
432       out.push_back(it->first);
433     }
434   } else {
435     scoped_refptr<base::RefCountedMemory> data;
436     size_t out_data_items = 0;
437     ::Atom out_type = None;
438
439     if (selection_requestor_.PerformBlockingConvertSelection(
440             selection_name,
441             atom_cache_.GetAtom(kTargets),
442             &data,
443             &out_data_items,
444             &out_type)) {
445       // Some apps return an |out_type| of "TARGETS". (crbug.com/377893)
446       if (out_type == XA_ATOM || out_type == atom_cache_.GetAtom(kTargets)) {
447         const ::Atom* atom_array =
448             reinterpret_cast<const ::Atom*>(data->front());
449         for (size_t i = 0; i < out_data_items; ++i)
450           out.push_back(atom_array[i]);
451       }
452     } else {
453       // There was no target list. Most Java apps doesn't offer a TARGETS list,
454       // even though they AWT to. They will offer individual text types if you
455       // ask. If this is the case we attempt to make sense of the contents as
456       // text. This is pretty unfortunate since it means we have to actually
457       // copy the data to see if it is available, but at least this path
458       // shouldn't be hit for conforming programs.
459       std::vector< ::Atom> types = GetTextAtoms();
460       for (std::vector< ::Atom>::const_iterator it = types.begin();
461            it != types.end(); ++it) {
462         ::Atom type = None;
463         if (selection_requestor_.PerformBlockingConvertSelection(selection_name,
464                                                                  *it,
465                                                                  NULL,
466                                                                  NULL,
467                                                                  &type) &&
468             type == *it) {
469           out.push_back(*it);
470         }
471       }
472     }
473   }
474
475   return TargetList(out, &atom_cache_);
476 }
477
478 std::vector<::Atom> ClipboardAuraX11::AuraX11Details::GetTextAtoms() const {
479   return GetTextAtomsFrom(&atom_cache_);
480 }
481
482 std::vector<::Atom> ClipboardAuraX11::AuraX11Details::GetAtomsForFormat(
483     const Clipboard::FormatType& format) {
484   std::vector< ::Atom> atoms;
485   atoms.push_back(atom_cache_.GetAtom(format.ToString().c_str()));
486   return atoms;
487 }
488
489 void ClipboardAuraX11::AuraX11Details::Clear(ClipboardType type) {
490   if (type == CLIPBOARD_TYPE_COPY_PASTE)
491     clipboard_owner_.ClearSelectionOwner();
492   else
493     primary_owner_.ClearSelectionOwner();
494 }
495
496 void ClipboardAuraX11::AuraX11Details::StoreCopyPasteDataAndWait() {
497   ::Atom selection = GetCopyPasteSelection();
498   if (XGetSelectionOwner(x_display_, selection) != x_window_)
499     return;
500
501   ::Atom clipboard_manager_atom = atom_cache_.GetAtom(kClipboardManager);
502   if (XGetSelectionOwner(x_display_, clipboard_manager_atom) == None)
503     return;
504
505   const SelectionFormatMap& format_map = LookupStorageForAtom(selection);
506   if (format_map.size() == 0)
507     return;
508   std::vector<Atom> targets = format_map.GetTypes();
509
510   base::TimeTicks start = base::TimeTicks::Now();
511   selection_requestor_.PerformBlockingConvertSelectionWithParameter(
512       atom_cache_.GetAtom(kClipboardManager),
513       atom_cache_.GetAtom(kSaveTargets),
514       targets);
515   UMA_HISTOGRAM_TIMES("Clipboard.X11StoreCopyPasteDuration",
516                       base::TimeTicks::Now() - start);
517 }
518
519 bool ClipboardAuraX11::AuraX11Details::CanDispatchEvent(
520     const PlatformEvent& event) {
521   if (event->xany.window == x_window_)
522     return true;
523
524   if (event->type == PropertyNotify) {
525     return primary_owner_.CanDispatchPropertyEvent(*event) ||
526         clipboard_owner_.CanDispatchPropertyEvent(*event) ||
527         selection_requestor_.CanDispatchPropertyEvent(*event);
528   }
529   return false;
530 }
531
532 uint32_t ClipboardAuraX11::AuraX11Details::DispatchEvent(
533     const PlatformEvent& xev) {
534   switch (xev->type) {
535     case SelectionRequest: {
536       if (xev->xselectionrequest.selection == XA_PRIMARY) {
537         primary_owner_.OnSelectionRequest(*xev);
538       } else {
539         // We should not get requests for the CLIPBOARD_MANAGER selection
540         // because we never take ownership of it.
541         DCHECK_EQ(GetCopyPasteSelection(), xev->xselectionrequest.selection);
542         clipboard_owner_.OnSelectionRequest(*xev);
543       }
544       break;
545     }
546     case SelectionNotify: {
547       selection_requestor_.OnSelectionNotify(*xev);
548       break;
549     }
550     case SelectionClear: {
551       if (xev->xselectionclear.selection == XA_PRIMARY) {
552         primary_owner_.OnSelectionClear(*xev);
553       } else {
554         // We should not get requests for the CLIPBOARD_MANAGER selection
555         // because we never take ownership of it.
556         DCHECK_EQ(GetCopyPasteSelection(), xev->xselection.selection);
557         clipboard_owner_.OnSelectionClear(*xev);
558         }
559       break;
560     }
561     case PropertyNotify: {
562       if (primary_owner_.CanDispatchPropertyEvent(*xev))
563         primary_owner_.OnPropertyEvent(*xev);
564       if (clipboard_owner_.CanDispatchPropertyEvent(*xev))
565         clipboard_owner_.OnPropertyEvent(*xev);
566       if (selection_requestor_.CanDispatchPropertyEvent(*xev))
567         selection_requestor_.OnPropertyEvent(*xev);
568       break;
569     }
570     default:
571       break;
572   }
573
574   return POST_DISPATCH_NONE;
575 }
576
577 ///////////////////////////////////////////////////////////////////////////////
578 // Various predefined FormatTypes.
579 // static
580 Clipboard::FormatType Clipboard::GetFormatType(
581     const std::string& format_string) {
582   return FormatType::Deserialize(format_string);
583 }
584
585 // static
586 const Clipboard::FormatType& Clipboard::GetUrlFormatType() {
587   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeURIList));
588   return type;
589 }
590
591 // static
592 const Clipboard::FormatType& Clipboard::GetUrlWFormatType() {
593   return GetUrlFormatType();
594 }
595
596 // static
597 const Clipboard::FormatType& Clipboard::GetPlainTextFormatType() {
598   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeText));
599   return type;
600 }
601
602 // static
603 const Clipboard::FormatType& Clipboard::GetPlainTextWFormatType() {
604   return GetPlainTextFormatType();
605 }
606
607 // static
608 const Clipboard::FormatType& Clipboard::GetFilenameFormatType() {
609   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeFilename));
610   return type;
611 }
612
613 // static
614 const Clipboard::FormatType& Clipboard::GetFilenameWFormatType() {
615   return Clipboard::GetFilenameFormatType();
616 }
617
618 // static
619 const Clipboard::FormatType& Clipboard::GetHtmlFormatType() {
620   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeHTML));
621   return type;
622 }
623
624 // static
625 const Clipboard::FormatType& Clipboard::GetRtfFormatType() {
626   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeRTF));
627   return type;
628 }
629
630 // static
631 const Clipboard::FormatType& Clipboard::GetBitmapFormatType() {
632   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypePNG));
633   return type;
634 }
635
636 // static
637 const Clipboard::FormatType& Clipboard::GetWebKitSmartPasteFormatType() {
638   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeWebkitSmartPaste));
639   return type;
640 }
641
642 // static
643 const Clipboard::FormatType& Clipboard::GetWebCustomDataFormatType() {
644   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeWebCustomData));
645   return type;
646 }
647
648 // static
649 const Clipboard::FormatType& Clipboard::GetPepperCustomDataFormatType() {
650   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypePepperCustomData));
651   return type;
652 }
653
654 ///////////////////////////////////////////////////////////////////////////////
655 // Clipboard factory method.
656 Clipboard* Clipboard::Create() {
657   return new ClipboardAuraX11;
658 }
659
660 ///////////////////////////////////////////////////////////////////////////////
661 // ClipboardAuraX11
662
663 ClipboardAuraX11::ClipboardAuraX11() : aurax11_details_(new AuraX11Details) {
664   DCHECK(CalledOnValidThread());
665 }
666
667 ClipboardAuraX11::~ClipboardAuraX11() {
668   DCHECK(CalledOnValidThread());
669
670   aurax11_details_->StoreCopyPasteDataAndWait();
671 }
672
673 uint64 ClipboardAuraX11::GetSequenceNumber(ClipboardType type) {
674   DCHECK(CalledOnValidThread());
675   if (type == CLIPBOARD_TYPE_COPY_PASTE)
676     return SelectionChangeObserver::GetInstance()->clipboard_sequence_number();
677   else
678     return SelectionChangeObserver::GetInstance()->primary_sequence_number();
679 }
680
681 bool ClipboardAuraX11::IsFormatAvailable(const FormatType& format,
682                                          ClipboardType type) const {
683   DCHECK(CalledOnValidThread());
684   DCHECK(IsSupportedClipboardType(type));
685
686   TargetList target_list = aurax11_details_->WaitAndGetTargetsList(type);
687   if (format.Equals(GetPlainTextFormatType()) ||
688       format.Equals(GetUrlFormatType())) {
689     return target_list.ContainsText();
690   }
691   return target_list.ContainsFormat(format);
692 }
693
694 void ClipboardAuraX11::Clear(ClipboardType type) {
695   DCHECK(CalledOnValidThread());
696   DCHECK(IsSupportedClipboardType(type));
697   aurax11_details_->Clear(type);
698 }
699
700 void ClipboardAuraX11::ReadAvailableTypes(ClipboardType type,
701                                           std::vector<base::string16>* types,
702                                           bool* contains_filenames) const {
703   DCHECK(CalledOnValidThread());
704   if (!types || !contains_filenames) {
705     NOTREACHED();
706     return;
707   }
708
709   TargetList target_list = aurax11_details_->WaitAndGetTargetsList(type);
710
711   types->clear();
712
713   if (target_list.ContainsText())
714     types->push_back(base::UTF8ToUTF16(kMimeTypeText));
715   if (target_list.ContainsFormat(GetHtmlFormatType()))
716     types->push_back(base::UTF8ToUTF16(kMimeTypeHTML));
717   if (target_list.ContainsFormat(GetRtfFormatType()))
718     types->push_back(base::UTF8ToUTF16(kMimeTypeRTF));
719   if (target_list.ContainsFormat(GetBitmapFormatType()))
720     types->push_back(base::UTF8ToUTF16(kMimeTypePNG));
721   *contains_filenames = false;
722
723   SelectionData data(aurax11_details_->RequestAndWaitForTypes(
724       type, aurax11_details_->GetAtomsForFormat(GetWebCustomDataFormatType())));
725   if (data.IsValid())
726     ReadCustomDataTypes(data.GetData(), data.GetSize(), types);
727 }
728
729 void ClipboardAuraX11::ReadText(ClipboardType type,
730                                 base::string16* result) const {
731   DCHECK(CalledOnValidThread());
732
733   SelectionData data(aurax11_details_->RequestAndWaitForTypes(
734       type, aurax11_details_->GetTextAtoms()));
735   if (data.IsValid()) {
736     std::string text = data.GetText();
737     *result = base::UTF8ToUTF16(text);
738   }
739 }
740
741 void ClipboardAuraX11::ReadAsciiText(ClipboardType type,
742                                      std::string* result) const {
743   DCHECK(CalledOnValidThread());
744
745   SelectionData data(aurax11_details_->RequestAndWaitForTypes(
746       type, aurax11_details_->GetTextAtoms()));
747   if (data.IsValid())
748     result->assign(data.GetText());
749 }
750
751 // TODO(estade): handle different charsets.
752 // TODO(port): set *src_url.
753 void ClipboardAuraX11::ReadHTML(ClipboardType type,
754                                 base::string16* markup,
755                                 std::string* src_url,
756                                 uint32* fragment_start,
757                                 uint32* fragment_end) const {
758   DCHECK(CalledOnValidThread());
759   markup->clear();
760   if (src_url)
761     src_url->clear();
762   *fragment_start = 0;
763   *fragment_end = 0;
764
765   SelectionData data(aurax11_details_->RequestAndWaitForTypes(
766       type, aurax11_details_->GetAtomsForFormat(GetHtmlFormatType())));
767   if (data.IsValid()) {
768     *markup = data.GetHtml();
769
770     *fragment_start = 0;
771     DCHECK(markup->length() <= kuint32max);
772     *fragment_end = static_cast<uint32>(markup->length());
773   }
774 }
775
776 void ClipboardAuraX11::ReadRTF(ClipboardType type, std::string* result) const {
777   DCHECK(CalledOnValidThread());
778
779   SelectionData data(aurax11_details_->RequestAndWaitForTypes(
780       type, aurax11_details_->GetAtomsForFormat(GetRtfFormatType())));
781   if (data.IsValid())
782     data.AssignTo(result);
783 }
784
785 SkBitmap ClipboardAuraX11::ReadImage(ClipboardType type) const {
786   DCHECK(CalledOnValidThread());
787
788   SelectionData data(aurax11_details_->RequestAndWaitForTypes(
789       type, aurax11_details_->GetAtomsForFormat(GetBitmapFormatType())));
790   if (data.IsValid()) {
791     SkBitmap bitmap;
792     if (gfx::PNGCodec::Decode(data.GetData(), data.GetSize(), &bitmap))
793       return SkBitmap(bitmap);
794   }
795
796   return SkBitmap();
797 }
798
799 void ClipboardAuraX11::ReadCustomData(ClipboardType clipboard_type,
800                                       const base::string16& type,
801                                       base::string16* result) const {
802   DCHECK(CalledOnValidThread());
803
804   SelectionData data(aurax11_details_->RequestAndWaitForTypes(
805       clipboard_type,
806       aurax11_details_->GetAtomsForFormat(GetWebCustomDataFormatType())));
807   if (data.IsValid())
808     ReadCustomDataForType(data.GetData(), data.GetSize(), type, result);
809 }
810
811 void ClipboardAuraX11::ReadBookmark(base::string16* title,
812                                     std::string* url) const {
813   DCHECK(CalledOnValidThread());
814   // TODO(erg): This was left NOTIMPLEMENTED() in the gtk port too.
815   NOTIMPLEMENTED();
816 }
817
818 void ClipboardAuraX11::ReadData(const FormatType& format,
819                                 std::string* result) const {
820   DCHECK(CalledOnValidThread());
821
822   SelectionData data(aurax11_details_->RequestAndWaitForTypes(
823       CLIPBOARD_TYPE_COPY_PASTE, aurax11_details_->GetAtomsForFormat(format)));
824   if (data.IsValid())
825     data.AssignTo(result);
826 }
827
828 void ClipboardAuraX11::WriteObjects(ClipboardType type,
829                                     const ObjectMap& objects) {
830   DCHECK(CalledOnValidThread());
831   DCHECK(IsSupportedClipboardType(type));
832
833   aurax11_details_->CreateNewClipboardData();
834   for (ObjectMap::const_iterator iter = objects.begin(); iter != objects.end();
835        ++iter) {
836     DispatchObject(static_cast<ObjectType>(iter->first), iter->second);
837   }
838   aurax11_details_->TakeOwnershipOfSelection(type);
839
840   if (type == CLIPBOARD_TYPE_COPY_PASTE) {
841     ObjectMap::const_iterator text_iter = objects.find(CBF_TEXT);
842     if (text_iter != objects.end()) {
843       aurax11_details_->CreateNewClipboardData();
844       const ObjectMapParams& params_vector = text_iter->second;
845       if (params_vector.size()) {
846         const ObjectMapParam& char_vector = params_vector[0];
847         if (char_vector.size())
848           WriteText(&char_vector.front(), char_vector.size());
849       }
850       aurax11_details_->TakeOwnershipOfSelection(CLIPBOARD_TYPE_SELECTION);
851     }
852   }
853 }
854
855 void ClipboardAuraX11::WriteText(const char* text_data, size_t text_len) {
856   std::string str(text_data, text_len);
857   scoped_refptr<base::RefCountedMemory> mem(
858       base::RefCountedString::TakeString(&str));
859
860   aurax11_details_->InsertMapping(kMimeTypeText, mem);
861   aurax11_details_->InsertMapping(kText, mem);
862   aurax11_details_->InsertMapping(kString, mem);
863   aurax11_details_->InsertMapping(kUtf8String, mem);
864 }
865
866 void ClipboardAuraX11::WriteHTML(const char* markup_data,
867                                  size_t markup_len,
868                                  const char* url_data,
869                                  size_t url_len) {
870   // TODO(estade): We need to expand relative links with |url_data|.
871   static const char* html_prefix = "<meta http-equiv=\"content-type\" "
872                                    "content=\"text/html; charset=utf-8\">";
873   std::string data = html_prefix;
874   data += std::string(markup_data, markup_len);
875   // Some programs expect NULL-terminated data. See http://crbug.com/42624
876   data += '\0';
877
878   scoped_refptr<base::RefCountedMemory> mem(
879       base::RefCountedString::TakeString(&data));
880   aurax11_details_->InsertMapping(kMimeTypeHTML, mem);
881 }
882
883 void ClipboardAuraX11::WriteRTF(const char* rtf_data, size_t data_len) {
884   WriteData(GetRtfFormatType(), rtf_data, data_len);
885 }
886
887 void ClipboardAuraX11::WriteBookmark(const char* title_data,
888                                      size_t title_len,
889                                      const char* url_data,
890                                      size_t url_len) {
891   // Write as a mozilla url (UTF16: URL, newline, title).
892   base::string16 url = base::UTF8ToUTF16(std::string(url_data, url_len) + "\n");
893   base::string16 title = base::UTF8ToUTF16(std::string(title_data, title_len));
894
895   std::vector<unsigned char> data;
896   ui::AddString16ToVector(url, &data);
897   ui::AddString16ToVector(title, &data);
898   scoped_refptr<base::RefCountedMemory> mem(
899       base::RefCountedBytes::TakeVector(&data));
900
901   aurax11_details_->InsertMapping(kMimeTypeMozillaURL, mem);
902 }
903
904 // Write an extra flavor that signifies WebKit was the last to modify the
905 // pasteboard. This flavor has no data.
906 void ClipboardAuraX11::WriteWebSmartPaste() {
907   std::string empty;
908   aurax11_details_->InsertMapping(
909       kMimeTypeWebkitSmartPaste,
910       scoped_refptr<base::RefCountedMemory>(
911           base::RefCountedString::TakeString(&empty)));
912 }
913
914 void ClipboardAuraX11::WriteBitmap(const SkBitmap& bitmap) {
915   // Encode the bitmap as a PNG for transport.
916   std::vector<unsigned char> output;
917   if (gfx::PNGCodec::FastEncodeBGRASkBitmap(bitmap, false, &output)) {
918     aurax11_details_->InsertMapping(kMimeTypePNG,
919                                     base::RefCountedBytes::TakeVector(
920                                         &output));
921   }
922 }
923
924 void ClipboardAuraX11::WriteData(const FormatType& format,
925                                  const char* data_data,
926                                  size_t data_len) {
927   // We assume that certain mapping types are only written by trusted code.
928   // Therefore we must upkeep their integrity.
929   if (format.Equals(GetBitmapFormatType()))
930     return;
931
932   std::vector<unsigned char> bytes(data_data, data_data + data_len);
933   scoped_refptr<base::RefCountedMemory> mem(
934       base::RefCountedBytes::TakeVector(&bytes));
935   aurax11_details_->InsertMapping(format.ToString(), mem);
936 }
937
938 }  // namespace ui