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