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 <gtk/gtk.h>
      8 #include <X11/extensions/Xfixes.h>
      9 #include <X11/Xatom.h>
     10 #include <map>
     11 #include <set>
     12 #include <string>
     13 #include <utility>
     14 
     15 #include "base/basictypes.h"
     16 #include "base/files/file_path.h"
     17 #include "base/logging.h"
     18 #include "base/memory/singleton.h"
     19 #include "base/strings/utf_string_conversions.h"
     20 #include "third_party/skia/include/core/SkBitmap.h"
     21 #include "ui/base/clipboard/custom_data_helper.h"
     22 #include "ui/base/gtk/gtk_signal.h"
     23 #include "ui/base/gtk/scoped_gobject.h"
     24 #include "ui/base/x/x11_util.h"
     25 #include "ui/gfx/canvas.h"
     26 #include "ui/gfx/gtk_util.h"
     27 #include "ui/gfx/size.h"
     28 
     29 namespace ui {
     30 
     31 namespace {
     32 
     33 class SelectionChangeObserver {
     34  public:
     35   static SelectionChangeObserver* GetInstance();
     36 
     37   uint64 clipboard_sequence_number() const {
     38     return clipboard_sequence_number_;
     39   }
     40   uint64 primary_sequence_number() const { return primary_sequence_number_; }
     41 
     42  private:
     43   friend struct DefaultSingletonTraits<SelectionChangeObserver>;
     44 
     45   SelectionChangeObserver();
     46   ~SelectionChangeObserver();
     47 
     48   CHROMEG_CALLBACK_1(SelectionChangeObserver, GdkFilterReturn, OnXEvent,
     49                      GdkXEvent*, GdkEvent*);
     50 
     51   int event_base_;
     52   Atom clipboard_atom_;
     53   uint64 clipboard_sequence_number_;
     54   uint64 primary_sequence_number_;
     55 
     56   DISALLOW_COPY_AND_ASSIGN(SelectionChangeObserver);
     57 };
     58 
     59 SelectionChangeObserver::SelectionChangeObserver()
     60     : event_base_(-1),
     61       clipboard_atom_(None),
     62       clipboard_sequence_number_(0),
     63       primary_sequence_number_(0) {
     64   int ignored;
     65   if (XFixesQueryExtension(GetXDisplay(), &event_base_, &ignored)) {
     66     clipboard_atom_ = XInternAtom(GetXDisplay(), "CLIPBOARD", false);
     67     XFixesSelectSelectionInput(GetXDisplay(), GetX11RootWindow(),
     68                                clipboard_atom_,
     69                                XFixesSetSelectionOwnerNotifyMask |
     70                                XFixesSelectionWindowDestroyNotifyMask |
     71                                XFixesSelectionClientCloseNotifyMask);
     72     // This seems to be semi-optional. For some reason, registering for any
     73     // selection notify events seems to subscribe us to events for both the
     74     // primary and the clipboard buffers. Register anyway just to be safe.
     75     XFixesSelectSelectionInput(GetXDisplay(), GetX11RootWindow(),
     76                                XA_PRIMARY,
     77                                XFixesSetSelectionOwnerNotifyMask |
     78                                XFixesSelectionWindowDestroyNotifyMask |
     79                                XFixesSelectionClientCloseNotifyMask);
     80     gdk_window_add_filter(NULL, &SelectionChangeObserver::OnXEventThunk, this);
     81   }
     82 }
     83 
     84 SelectionChangeObserver::~SelectionChangeObserver() {
     85 }
     86 
     87 SelectionChangeObserver* SelectionChangeObserver::GetInstance() {
     88   return Singleton<SelectionChangeObserver>::get();
     89 }
     90 
     91 GdkFilterReturn SelectionChangeObserver::OnXEvent(GdkXEvent* xevent,
     92                                                   GdkEvent* event) {
     93   XEvent* xev = static_cast<XEvent*>(xevent);
     94 
     95   if (xev->type == event_base_ + XFixesSelectionNotify) {
     96     XFixesSelectionNotifyEvent* ev =
     97         reinterpret_cast<XFixesSelectionNotifyEvent*>(xev);
     98     if (ev->selection == clipboard_atom_) {
     99       clipboard_sequence_number_++;
    100     } else if (ev->selection == XA_PRIMARY) {
    101       primary_sequence_number_++;
    102     } else {
    103       DLOG(ERROR) << "Unexpected selection atom: " << ev->selection;
    104     }
    105   }
    106   return GDK_FILTER_CONTINUE;
    107 }
    108 
    109 const char kMimeTypeBitmap[] = "image/bmp";
    110 const char kMimeTypeMozillaURL[] = "text/x-moz-url";
    111 const char kMimeTypePepperCustomData[] = "chromium/x-pepper-custom-data";
    112 const char kMimeTypeWebkitSmartPaste[] = "chromium/x-webkit-paste";
    113 
    114 std::string GdkAtomToString(const GdkAtom& atom) {
    115   gchar* name = gdk_atom_name(atom);
    116   std::string rv(name);
    117   g_free(name);
    118   return rv;
    119 }
    120 
    121 GdkAtom StringToGdkAtom(const std::string& str) {
    122   return gdk_atom_intern(str.c_str(), FALSE);
    123 }
    124 
    125 // GtkClipboardGetFunc callback.
    126 // GTK will call this when an application wants data we copied to the clipboard.
    127 void GetData(GtkClipboard* clipboard,
    128              GtkSelectionData* selection_data,
    129              guint info,
    130              gpointer user_data) {
    131   Clipboard::TargetMap* data_map =
    132       reinterpret_cast<Clipboard::TargetMap*>(user_data);
    133 
    134   std::string target_string = GdkAtomToString(
    135       gtk_selection_data_get_target(selection_data));
    136   Clipboard::TargetMap::iterator iter = data_map->find(target_string);
    137 
    138   if (iter == data_map->end())
    139     return;
    140 
    141   if (target_string == kMimeTypeBitmap) {
    142     gtk_selection_data_set_pixbuf(selection_data,
    143         reinterpret_cast<GdkPixbuf*>(iter->second.first));
    144   } else {
    145     gtk_selection_data_set(selection_data,
    146                            gtk_selection_data_get_target(selection_data), 8,
    147                            reinterpret_cast<guchar*>(iter->second.first),
    148                            iter->second.second);
    149   }
    150 }
    151 
    152 // GtkClipboardClearFunc callback.
    153 // We are guaranteed this will be called exactly once for each call to
    154 // gtk_clipboard_set_with_data.
    155 void ClearData(GtkClipboard* /*clipboard*/,
    156                gpointer user_data) {
    157   Clipboard::TargetMap* map =
    158       reinterpret_cast<Clipboard::TargetMap*>(user_data);
    159   // The same data may be inserted under multiple keys, so use a set to
    160   // uniq them.
    161   std::set<char*> ptrs;
    162 
    163   for (Clipboard::TargetMap::iterator iter = map->begin();
    164        iter != map->end(); ++iter) {
    165     if (iter->first == kMimeTypeBitmap)
    166       g_object_unref(reinterpret_cast<GdkPixbuf*>(iter->second.first));
    167     else
    168       ptrs.insert(iter->second.first);
    169   }
    170 
    171   for (std::set<char*>::iterator iter = ptrs.begin();
    172        iter != ptrs.end(); ++iter) {
    173     delete[] *iter;
    174   }
    175 
    176   delete map;
    177 }
    178 
    179 }  // namespace
    180 
    181 Clipboard::FormatType::FormatType() : data_(GDK_NONE) {
    182 }
    183 
    184 Clipboard::FormatType::FormatType(const std::string& format_string)
    185     : data_(StringToGdkAtom(format_string)) {
    186 }
    187 
    188 Clipboard::FormatType::FormatType(const GdkAtom& native_format)
    189     : data_(native_format) {
    190 }
    191 
    192 Clipboard::FormatType::~FormatType() {
    193 }
    194 
    195 std::string Clipboard::FormatType::Serialize() const {
    196   return GdkAtomToString(data_);
    197 }
    198 
    199 // static
    200 Clipboard::FormatType Clipboard::FormatType::Deserialize(
    201     const std::string& serialization) {
    202   return FormatType(serialization);
    203 }
    204 
    205 bool Clipboard::FormatType::Equals(const FormatType& other) const {
    206   return data_ == other.data_;
    207 }
    208 
    209 Clipboard::Clipboard() : clipboard_data_(NULL) {
    210   DCHECK(CalledOnValidThread());
    211   clipboard_ = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
    212   primary_selection_ = gtk_clipboard_get(GDK_SELECTION_PRIMARY);
    213 }
    214 
    215 Clipboard::~Clipboard() {
    216   DCHECK(CalledOnValidThread());
    217   gtk_clipboard_store(clipboard_);
    218 }
    219 
    220 void Clipboard::WriteObjects(Buffer buffer, const ObjectMap& objects) {
    221   DCHECK(CalledOnValidThread());
    222   clipboard_data_ = new TargetMap();
    223 
    224   for (ObjectMap::const_iterator iter = objects.begin();
    225        iter != objects.end(); ++iter) {
    226     DispatchObject(static_cast<ObjectType>(iter->first), iter->second);
    227   }
    228   SetGtkClipboard(buffer);
    229 
    230   if (buffer == BUFFER_STANDARD) {
    231     ObjectMap::const_iterator text_iter = objects.find(CBF_TEXT);
    232     if (text_iter != objects.end()) {
    233       // Copy text and SourceTag to the selection clipboard.
    234       ObjectMap::const_iterator next_iter = text_iter;
    235       WriteObjects(BUFFER_SELECTION, ObjectMap(text_iter, ++next_iter));
    236     }
    237   }
    238 }
    239 
    240 // Take ownership of the GTK clipboard and inform it of the targets we support.
    241 void Clipboard::SetGtkClipboard(Buffer buffer) {
    242   scoped_ptr<GtkTargetEntry[]> targets(
    243       new GtkTargetEntry[clipboard_data_->size()]);
    244 
    245   int i = 0;
    246   for (Clipboard::TargetMap::iterator iter = clipboard_data_->begin();
    247        iter != clipboard_data_->end(); ++iter, ++i) {
    248     targets[i].target = const_cast<char*>(iter->first.c_str());
    249     targets[i].flags = 0;
    250     targets[i].info = 0;
    251   }
    252 
    253   GtkClipboard *clipboard = LookupBackingClipboard(buffer);
    254 
    255   if (gtk_clipboard_set_with_data(clipboard, targets.get(),
    256                                   clipboard_data_->size(),
    257                                   GetData, ClearData,
    258                                   clipboard_data_)) {
    259     gtk_clipboard_set_can_store(clipboard,
    260                                 targets.get(),
    261                                 clipboard_data_->size());
    262   }
    263 
    264   // clipboard_data_ now owned by the GtkClipboard.
    265   clipboard_data_ = NULL;
    266 }
    267 
    268 void Clipboard::WriteText(const char* text_data, size_t text_len) {
    269   char* data = new char[text_len];
    270   memcpy(data, text_data, text_len);
    271 
    272   InsertMapping(kMimeTypeText, data, text_len);
    273   InsertMapping("TEXT", data, text_len);
    274   InsertMapping("STRING", data, text_len);
    275   InsertMapping("UTF8_STRING", data, text_len);
    276   InsertMapping("COMPOUND_TEXT", data, text_len);
    277 }
    278 
    279 void Clipboard::WriteHTML(const char* markup_data,
    280                           size_t markup_len,
    281                           const char* url_data,
    282                           size_t url_len) {
    283   // TODO(estade): We need to expand relative links with |url_data|.
    284   static const char* html_prefix = "<meta http-equiv=\"content-type\" "
    285                                    "content=\"text/html; charset=utf-8\">";
    286   size_t html_prefix_len = strlen(html_prefix);
    287   size_t total_len = html_prefix_len + markup_len + 1;
    288 
    289   char* data = new char[total_len];
    290   snprintf(data, total_len, "%s", html_prefix);
    291   memcpy(data + html_prefix_len, markup_data, markup_len);
    292   // Some programs expect NULL-terminated data. See http://crbug.com/42624
    293   data[total_len - 1] = '\0';
    294 
    295   InsertMapping(kMimeTypeHTML, data, total_len);
    296 }
    297 
    298 void Clipboard::WriteRTF(const char* rtf_data, size_t data_len) {
    299   WriteData(GetRtfFormatType(), rtf_data, data_len);
    300 }
    301 
    302 // Write an extra flavor that signifies WebKit was the last to modify the
    303 // pasteboard. This flavor has no data.
    304 void Clipboard::WriteWebSmartPaste() {
    305   InsertMapping(kMimeTypeWebkitSmartPaste, NULL, 0);
    306 }
    307 
    308 void Clipboard::WriteBitmap(const char* pixel_data, const char* size_data) {
    309   const gfx::Size* size = reinterpret_cast<const gfx::Size*>(size_data);
    310 
    311   // Adopt the pixels into a SkBitmap. Note that the pixel order in memory is
    312   // actually BGRA.
    313   SkBitmap bitmap;
    314   bitmap.setConfig(SkBitmap::kARGB_8888_Config, size->width(), size->height());
    315   bitmap.setPixels(const_cast<char*>(pixel_data));
    316   GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(bitmap);
    317 
    318   // We store the GdkPixbuf*, and the size_t half of the pair is meaningless.
    319   // Note that this contrasts with the vast majority of entries in our target
    320   // map, which directly store the data and its length.
    321   InsertMapping(kMimeTypeBitmap, reinterpret_cast<char*>(pixbuf), 0);
    322 }
    323 
    324 void Clipboard::WriteBookmark(const char* title_data, size_t title_len,
    325                               const char* url_data, size_t url_len) {
    326   // Write as a mozilla url (UTF16: URL, newline, title).
    327   string16 url = UTF8ToUTF16(std::string(url_data, url_len) + "\n");
    328   string16 title = UTF8ToUTF16(std::string(title_data, title_len));
    329   if (title.length() >= std::numeric_limits<size_t>::max() / 4 ||
    330       url.length() >= std::numeric_limits<size_t>::max() / 4)
    331     return;
    332   size_t data_len = 2 * (title.length() + url.length());
    333 
    334   char* data = new char[data_len];
    335   memcpy(data, url.data(), 2 * url.length());
    336   memcpy(data + 2 * url.length(), title.data(), 2 * title.length());
    337   InsertMapping(kMimeTypeMozillaURL, data, data_len);
    338 }
    339 
    340 void Clipboard::WriteData(const FormatType& format,
    341                           const char* data_data,
    342                           size_t data_len) {
    343   // We assume that certain mapping types are only written by trusted code.
    344   // Therefore we must upkeep their integrity.
    345   if (format.Equals(GetBitmapFormatType()))
    346     return;
    347   char* data = new char[data_len];
    348   memcpy(data, data_data, data_len);
    349   // TODO(dcheng): Maybe this map should use GdkAtoms...
    350   InsertMapping(GdkAtomToString(format.ToGdkAtom()).c_str(), data, data_len);
    351 }
    352 
    353 // We do not use gtk_clipboard_wait_is_target_available because of
    354 // a bug with the gtk clipboard. It caches the available targets
    355 // and does not always refresh the cache when it is appropriate.
    356 bool Clipboard::IsFormatAvailable(const Clipboard::FormatType& format,
    357                                   Clipboard::Buffer buffer) const {
    358   DCHECK(CalledOnValidThread());
    359   GtkClipboard* clipboard = LookupBackingClipboard(buffer);
    360   if (clipboard == NULL)
    361     return false;
    362 
    363   bool retval = false;
    364   GtkSelectionData* data = gtk_clipboard_wait_for_contents(
    365       clipboard, gdk_atom_intern_static_string("TARGETS"));
    366 
    367   bool format_is_plain_text = GetPlainTextFormatType().Equals(format);
    368   if (format_is_plain_text) {
    369     // This tries a number of common text targets.
    370     if (data) {
    371       retval = gtk_selection_data_targets_include_text(data);
    372     }
    373     // Some programs like Java decide to set an empty TARGETS list, so even if
    374     // data is not NULL, we still have to fall back.
    375     if (!retval) {
    376       // Some programs post data to the clipboard without any targets. If this
    377       // is the case we attempt to make sense of the contents as text. This is
    378       // pretty unfortunate since it means we have to actually copy the data to
    379       // see if it is available, but at least this path shouldn't be hit for
    380       // conforming programs.
    381       gchar* text = gtk_clipboard_wait_for_text(clipboard);
    382       if (text) {
    383         g_free(text);
    384         retval = true;
    385       }
    386     }
    387   } else if (data) {
    388     GdkAtom* targets = NULL;
    389     int num = 0;
    390     gtk_selection_data_get_targets(data, &targets, &num);
    391 
    392     for (int i = 0; i < num; i++) {
    393       if (targets[i] == format.ToGdkAtom()) {
    394         retval = true;
    395         break;
    396       }
    397     }
    398 
    399     g_free(targets);
    400   }
    401 
    402   if (data)
    403     gtk_selection_data_free(data);
    404 
    405   return retval;
    406 }
    407 
    408 void Clipboard::Clear(Clipboard::Buffer buffer) {
    409   DCHECK(CalledOnValidThread());
    410   GtkClipboard* clipboard = LookupBackingClipboard(buffer);
    411   if (clipboard == NULL)
    412     return;
    413   gtk_clipboard_clear(clipboard);
    414 }
    415 
    416 void Clipboard::ReadAvailableTypes(Clipboard::Buffer buffer,
    417                                    std::vector<string16>* types,
    418                                    bool* contains_filenames) const {
    419   DCHECK(CalledOnValidThread());
    420   if (!types || !contains_filenames) {
    421     NOTREACHED();
    422     return;
    423   }
    424 
    425   types->clear();
    426   if (IsFormatAvailable(GetPlainTextFormatType(), buffer))
    427     types->push_back(UTF8ToUTF16(kMimeTypeText));
    428   if (IsFormatAvailable(GetHtmlFormatType(), buffer))
    429     types->push_back(UTF8ToUTF16(kMimeTypeHTML));
    430   if (IsFormatAvailable(GetRtfFormatType(), buffer))
    431     types->push_back(UTF8ToUTF16(kMimeTypeRTF));
    432   if (IsFormatAvailable(GetBitmapFormatType(), buffer))
    433     types->push_back(UTF8ToUTF16(kMimeTypePNG));
    434   *contains_filenames = false;
    435 
    436   GtkClipboard* clipboard = LookupBackingClipboard(buffer);
    437   if (!clipboard)
    438     return;
    439 
    440   GtkSelectionData* data = gtk_clipboard_wait_for_contents(
    441       clipboard, GetWebCustomDataFormatType().ToGdkAtom());
    442   if (!data)
    443     return;
    444   ReadCustomDataTypes(gtk_selection_data_get_data(data),
    445                       gtk_selection_data_get_length(data),
    446                       types);
    447   gtk_selection_data_free(data);
    448 }
    449 
    450 
    451 void Clipboard::ReadText(Clipboard::Buffer buffer, string16* result) const {
    452   DCHECK(CalledOnValidThread());
    453   GtkClipboard* clipboard = LookupBackingClipboard(buffer);
    454   if (clipboard == NULL)
    455     return;
    456 
    457   result->clear();
    458   gchar* text = gtk_clipboard_wait_for_text(clipboard);
    459 
    460   if (text == NULL)
    461     return;
    462 
    463   // TODO(estade): do we want to handle the possible error here?
    464   UTF8ToUTF16(text, strlen(text), result);
    465   g_free(text);
    466 }
    467 
    468 void Clipboard::ReadAsciiText(Clipboard::Buffer buffer,
    469                               std::string* result) const {
    470   DCHECK(CalledOnValidThread());
    471   GtkClipboard* clipboard = LookupBackingClipboard(buffer);
    472   if (clipboard == NULL)
    473     return;
    474 
    475   result->clear();
    476   gchar* text = gtk_clipboard_wait_for_text(clipboard);
    477 
    478   if (text == NULL)
    479     return;
    480 
    481   result->assign(text);
    482   g_free(text);
    483 }
    484 
    485 // TODO(estade): handle different charsets.
    486 // TODO(port): set *src_url.
    487 void Clipboard::ReadHTML(Clipboard::Buffer buffer, string16* markup,
    488                          std::string* src_url, uint32* fragment_start,
    489                          uint32* fragment_end) const {
    490   DCHECK(CalledOnValidThread());
    491   markup->clear();
    492   if (src_url)
    493     src_url->clear();
    494   *fragment_start = 0;
    495   *fragment_end = 0;
    496 
    497   GtkClipboard* clipboard = LookupBackingClipboard(buffer);
    498   if (clipboard == NULL)
    499     return;
    500   GtkSelectionData* data = gtk_clipboard_wait_for_contents(clipboard,
    501       GetHtmlFormatType().ToGdkAtom());
    502 
    503   if (!data)
    504     return;
    505 
    506   // If the data starts with 0xFEFF, i.e., Byte Order Mark, assume it is
    507   // UTF-16, otherwise assume UTF-8.
    508   gint data_length = gtk_selection_data_get_length(data);
    509   const guchar* raw_data = gtk_selection_data_get_data(data);
    510 
    511   if (data_length >= 2 &&
    512       reinterpret_cast<const uint16_t*>(raw_data)[0] == 0xFEFF) {
    513     markup->assign(reinterpret_cast<const uint16_t*>(raw_data) + 1,
    514                    (data_length / 2) - 1);
    515   } else {
    516     UTF8ToUTF16(reinterpret_cast<const char*>(raw_data), data_length, markup);
    517   }
    518 
    519   // If there is a terminating NULL, drop it.
    520   if (!markup->empty() && markup->at(markup->length() - 1) == '\0')
    521     markup->resize(markup->length() - 1);
    522 
    523   *fragment_start = 0;
    524   DCHECK(markup->length() <= kuint32max);
    525   *fragment_end = static_cast<uint32>(markup->length());
    526 
    527   gtk_selection_data_free(data);
    528 }
    529 
    530 void Clipboard::ReadRTF(Buffer buffer, std::string* result) const {
    531   DCHECK(CalledOnValidThread());
    532   ReadData(GetRtfFormatType(), result);
    533 }
    534 
    535 SkBitmap Clipboard::ReadImage(Buffer buffer) const {
    536   DCHECK(CalledOnValidThread());
    537   ScopedGObject<GdkPixbuf>::Type pixbuf(
    538       gtk_clipboard_wait_for_image(clipboard_));
    539   if (!pixbuf.get())
    540     return SkBitmap();
    541 
    542   gfx::Canvas canvas(gfx::Size(gdk_pixbuf_get_width(pixbuf.get()),
    543                                gdk_pixbuf_get_height(pixbuf.get())),
    544                      ui::SCALE_FACTOR_100P,
    545                      false);
    546   {
    547     skia::ScopedPlatformPaint scoped_platform_paint(canvas.sk_canvas());
    548     cairo_t* context = scoped_platform_paint.GetPlatformSurface();
    549     gdk_cairo_set_source_pixbuf(context, pixbuf.get(), 0.0, 0.0);
    550     cairo_paint(context);
    551   }
    552   return canvas.ExtractImageRep().sk_bitmap();
    553 }
    554 
    555 void Clipboard::ReadCustomData(Buffer buffer,
    556                                const string16& type,
    557                                string16* result) const {
    558   DCHECK(CalledOnValidThread());
    559   GtkClipboard* clipboard = LookupBackingClipboard(buffer);
    560   if (!clipboard)
    561     return;
    562 
    563   GtkSelectionData* data = gtk_clipboard_wait_for_contents(
    564       clipboard, GetWebCustomDataFormatType().ToGdkAtom());
    565   if (!data)
    566     return;
    567   ReadCustomDataForType(gtk_selection_data_get_data(data),
    568                         gtk_selection_data_get_length(data),
    569                         type, result);
    570   gtk_selection_data_free(data);
    571 }
    572 
    573 void Clipboard::ReadBookmark(string16* title, std::string* url) const {
    574   // TODO(estade): implement this.
    575   NOTIMPLEMENTED();
    576 }
    577 
    578 void Clipboard::ReadData(const FormatType& format, std::string* result) const {
    579   DCHECK(CalledOnValidThread());
    580   result->clear();
    581   GtkSelectionData* data =
    582       gtk_clipboard_wait_for_contents(clipboard_, format.ToGdkAtom());
    583   if (!data)
    584     return;
    585   result->assign(reinterpret_cast<const char*>(
    586                      gtk_selection_data_get_data(data)),
    587                  gtk_selection_data_get_length(data));
    588   gtk_selection_data_free(data);
    589 }
    590 
    591 uint64 Clipboard::GetSequenceNumber(Buffer buffer) {
    592   DCHECK(CalledOnValidThread());
    593   if (buffer == BUFFER_STANDARD)
    594     return SelectionChangeObserver::GetInstance()->clipboard_sequence_number();
    595   else
    596     return SelectionChangeObserver::GetInstance()->primary_sequence_number();
    597 }
    598 
    599 //static
    600 Clipboard::FormatType Clipboard::GetFormatType(
    601     const std::string& format_string) {
    602   return FormatType::Deserialize(format_string);
    603 }
    604 
    605 // static
    606 const Clipboard::FormatType& Clipboard::GetPlainTextFormatType() {
    607   CR_DEFINE_STATIC_LOCAL(
    608       FormatType, type, (GDK_TARGET_STRING));
    609   return type;
    610 }
    611 
    612 // static
    613 const Clipboard::FormatType& Clipboard::GetPlainTextWFormatType() {
    614   return GetPlainTextFormatType();
    615 }
    616 
    617 // static
    618 const Clipboard::FormatType& Clipboard::GetUrlFormatType() {
    619   return GetPlainTextFormatType();
    620 }
    621 
    622 // static
    623 const Clipboard::FormatType& Clipboard::GetUrlWFormatType() {
    624   return GetPlainTextWFormatType();
    625 }
    626 
    627 // static
    628 const Clipboard::FormatType& Clipboard::GetHtmlFormatType() {
    629   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeHTML));
    630   return type;
    631 }
    632 
    633 // static
    634 const Clipboard::FormatType& Clipboard::GetRtfFormatType() {
    635   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeRTF));
    636   return type;
    637 }
    638 
    639 // static
    640 const Clipboard::FormatType& Clipboard::GetBitmapFormatType() {
    641   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeBitmap));
    642   return type;
    643 }
    644 
    645 // static
    646 const Clipboard::FormatType& Clipboard::GetWebKitSmartPasteFormatType() {
    647   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeWebkitSmartPaste));
    648   return type;
    649 }
    650 
    651 // static
    652 const Clipboard::FormatType& Clipboard::GetWebCustomDataFormatType() {
    653   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeWebCustomData));
    654   return type;
    655 }
    656 
    657 // static
    658 const Clipboard::FormatType& Clipboard::GetPepperCustomDataFormatType() {
    659   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypePepperCustomData));
    660   return type;
    661 }
    662 
    663 void Clipboard::InsertMapping(const char* key,
    664                               char* data,
    665                               size_t data_len) {
    666   DCHECK(clipboard_data_->find(key) == clipboard_data_->end());
    667   (*clipboard_data_)[key] = std::make_pair(data, data_len);
    668 }
    669 
    670 GtkClipboard* Clipboard::LookupBackingClipboard(Buffer clipboard) const {
    671   switch (clipboard) {
    672     case BUFFER_STANDARD:
    673       return clipboard_;
    674     case BUFFER_SELECTION:
    675       return primary_selection_;
    676     default:
    677       NOTREACHED();
    678       return NULL;
    679   }
    680 }
    681 
    682 }  // namespace ui
    683