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