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 <list>
      8 
      9 #include "base/basictypes.h"
     10 #include "base/files/file_path.h"
     11 #include "base/logging.h"
     12 #include "base/memory/scoped_ptr.h"
     13 #include "base/stl_util.h"
     14 #include "base/strings/utf_string_conversions.h"
     15 #include "third_party/skia/include/core/SkBitmap.h"
     16 #include "ui/base/clipboard/custom_data_helper.h"
     17 #include "ui/gfx/size.h"
     18 
     19 namespace ui {
     20 
     21 namespace {
     22 const char kMimeTypeFilename[] = "chromium/filename";
     23 const char kMimeTypeBitmap[] = "image/bmp";
     24 const char kMimeTypePepperCustomData[] = "chromium/x-pepper-custom-data";
     25 const char kMimeTypeWebkitSmartPaste[] = "chromium/x-webkit-paste";
     26 const size_t kMaxClipboardSize = 1;
     27 
     28 // Clipboard data format used by AuraClipboard.
     29 enum AuraClipboardFormat {
     30   TEXT      = 1 << 0,
     31   HTML      = 1 << 1,
     32   RTF       = 1 << 2,
     33   BOOKMARK  = 1 << 3,
     34   BITMAP    = 1 << 4,
     35   CUSTOM    = 1 << 5,
     36   WEB       = 1 << 6,
     37 };
     38 
     39 // ClipboardData contains data copied to the Clipboard for a variety of formats.
     40 // It mostly just provides APIs to cleanly access and manipulate this data.
     41 class ClipboardData {
     42  public:
     43   ClipboardData()
     44       : web_smart_paste_(false),
     45         format_(0) {}
     46 
     47   virtual ~ClipboardData() {}
     48 
     49   // Bitmask of AuraClipboardFormat types.
     50   const int format() const { return format_; }
     51 
     52   const std::string& text() const { return text_; }
     53   void set_text(const std::string& text) {
     54     text_ = text;
     55     format_ |= TEXT;
     56   }
     57 
     58   const std::string& markup_data() const { return markup_data_; }
     59   void set_markup_data(const std::string& markup_data) {
     60     markup_data_ = markup_data;
     61     format_ |= HTML;
     62   }
     63 
     64   const std::string& rtf_data() const { return rtf_data_; }
     65   void SetRTFData(const std::string& rtf_data) {
     66     rtf_data_ = rtf_data;
     67     format_ |= RTF;
     68   }
     69 
     70   const std::string& url() const { return url_; }
     71   void set_url(const std::string& url) {
     72     url_ = url;
     73     format_ |= HTML;
     74   }
     75 
     76   const std::string& bookmark_title() const { return bookmark_title_; }
     77   void set_bookmark_title(const std::string& bookmark_title) {
     78     bookmark_title_ = bookmark_title;
     79     format_ |= BOOKMARK;
     80   }
     81 
     82   const std::string& bookmark_url() const { return bookmark_url_; }
     83   void set_bookmark_url(const std::string& bookmark_url) {
     84     bookmark_url_ = bookmark_url;
     85     format_ |= BOOKMARK;
     86   }
     87 
     88   const SkBitmap& bitmap() const { return bitmap_; }
     89   void SetBitmapData(const SkBitmap& bitmap) {
     90     bitmap.copyTo(&bitmap_, bitmap.getConfig());
     91     format_ |= BITMAP;
     92   }
     93 
     94   const std::string& custom_data_format() const { return custom_data_format_; }
     95   const std::string& custom_data_data() const { return custom_data_data_; }
     96   void SetCustomData(const std::string& data_format,
     97                      const std::string& data_data) {
     98     if (data_data.size() == 0) {
     99       custom_data_data_.clear();
    100       custom_data_format_.clear();
    101       return;
    102     }
    103     custom_data_data_ = data_data;
    104     custom_data_format_ = data_format;
    105     format_ |= CUSTOM;
    106   }
    107 
    108   bool web_smart_paste() const { return web_smart_paste_; }
    109   void set_web_smart_paste(bool web_smart_paste) {
    110     web_smart_paste_ = web_smart_paste;
    111     format_ |= WEB;
    112   }
    113 
    114  private:
    115   // Plain text in UTF8 format.
    116   std::string text_;
    117 
    118   // HTML markup data in UTF8 format.
    119   std::string markup_data_;
    120   std::string url_;
    121 
    122   // RTF data.
    123   std::string rtf_data_;
    124 
    125   // Bookmark title in UTF8 format.
    126   std::string bookmark_title_;
    127   std::string bookmark_url_;
    128 
    129   // Filenames.
    130   std::vector<std::string> files_;
    131 
    132   // Bitmap images.
    133   SkBitmap bitmap_;
    134 
    135   // Data with custom format.
    136   std::string custom_data_format_;
    137   std::string custom_data_data_;
    138 
    139   // WebKit smart paste data.
    140   bool web_smart_paste_;
    141 
    142   int format_;
    143 
    144   DISALLOW_COPY_AND_ASSIGN(ClipboardData);
    145 };
    146 
    147 // Platform clipboard implementation for Aura. This handles things like format
    148 // conversion, versioning of clipboard items etc. The goal is to roughly provide
    149 // a substitute to platform clipboards on other platforms such as GtkClipboard
    150 // on gtk or winapi clipboard on win.
    151 class AuraClipboard {
    152  public:
    153   AuraClipboard() {}
    154 
    155   ~AuraClipboard() {
    156     Clear();
    157   }
    158 
    159   void Clear() {
    160     STLDeleteContainerPointers(data_list_.begin(), data_list_.end());
    161     data_list_.clear();
    162   }
    163 
    164   // Returns the number of entries currently in the clipboard stack.
    165   size_t GetNumClipboardEntries() {
    166     return data_list_.size();
    167   }
    168 
    169   // Returns the data currently on the top of the clipboard stack, NULL if the
    170   // clipboard stack is empty.
    171   const ClipboardData* GetData() const {
    172     if (data_list_.empty())
    173       return NULL;
    174     return data_list_.front();
    175   }
    176 
    177   // Returns true if the data on top of the clipboard stack has format |format|
    178   // or another format that can be converted to |format|.
    179   bool IsFormatAvailable(AuraClipboardFormat format) const {
    180     switch (format) {
    181       case TEXT:
    182         return HasFormat(TEXT) || HasFormat(BOOKMARK);
    183       default:
    184         return HasFormat(format);
    185     }
    186   }
    187 
    188   // Reads text from the data at the top of clipboard stack.
    189   void ReadText(string16* result) const {
    190     std::string utf8_result;
    191     ReadAsciiText(&utf8_result);
    192     *result = UTF8ToUTF16(utf8_result);
    193   }
    194 
    195   // Reads ascii text from the data at the top of clipboard stack.
    196   void ReadAsciiText(std::string* result) const {
    197     result->clear();
    198     const ClipboardData* data = GetData();
    199     if (!data)
    200       return;
    201     if (HasFormat(TEXT))
    202       *result = data->text();
    203     else if (HasFormat(HTML))
    204       *result = data->markup_data();
    205     else if (HasFormat(BOOKMARK))
    206       *result = data->bookmark_url();
    207   }
    208 
    209   // Reads HTML from the data at the top of clipboard stack.
    210   void ReadHTML(string16* markup,
    211                 std::string* src_url,
    212                 uint32* fragment_start,
    213                 uint32* fragment_end) const {
    214     markup->clear();
    215     if (src_url)
    216       src_url->clear();
    217     *fragment_start = 0;
    218     *fragment_end = 0;
    219 
    220     if (!HasFormat(HTML))
    221       return;
    222 
    223     const ClipboardData* data = GetData();
    224     *markup = UTF8ToUTF16(data->markup_data());
    225     *src_url = data->url();
    226 
    227     *fragment_start = 0;
    228     DCHECK_LE(markup->length(), kuint32max);
    229     *fragment_end = static_cast<uint32>(markup->length());
    230   }
    231 
    232   // Reads RTF from the data at the top of clipboard stack.
    233   void ReadRTF(std::string* result) const {
    234     result->clear();
    235     const ClipboardData* data = GetData();
    236     if (!HasFormat(RTF))
    237       return;
    238 
    239     *result = data->rtf_data();
    240   }
    241 
    242   // Reads image from the data at the top of clipboard stack.
    243   SkBitmap ReadImage() const {
    244     SkBitmap img;
    245     if (!HasFormat(BITMAP))
    246       return img;
    247 
    248     // A shallow copy should be fine here, but just to be safe...
    249     const SkBitmap& clipboard_bitmap = GetData()->bitmap();
    250     clipboard_bitmap.copyTo(&img, clipboard_bitmap.getConfig());
    251     return img;
    252   }
    253 
    254   // Reads data of type |type| from the data at the top of clipboard stack.
    255   void ReadCustomData(const string16& type, string16* result) const {
    256     result->clear();
    257     const ClipboardData* data = GetData();
    258     if (!HasFormat(CUSTOM))
    259       return;
    260 
    261     ui::ReadCustomDataForType(data->custom_data_data().c_str(),
    262         data->custom_data_data().size(),
    263         type, result);
    264   }
    265 
    266   // Reads bookmark from the data at the top of clipboard stack.
    267   void ReadBookmark(string16* title, std::string* url) const {
    268     title->clear();
    269     url->clear();
    270     if (!HasFormat(BOOKMARK))
    271       return;
    272 
    273     const ClipboardData* data = GetData();
    274     *title = UTF8ToUTF16(data->bookmark_title());
    275     *url = data->bookmark_url();
    276   }
    277 
    278   void ReadData(const std::string& type, std::string* result) const {
    279     result->clear();
    280     const ClipboardData* data = GetData();
    281     if (!HasFormat(CUSTOM) || type != data->custom_data_format())
    282       return;
    283 
    284     *result = data->custom_data_data();
    285   }
    286 
    287   // Writes |data| to the top of the clipboard stack.
    288   void WriteData(ClipboardData* data) {
    289     DCHECK(data);
    290     AddToListEnsuringSize(data);
    291   }
    292 
    293  private:
    294   // True if the data on top of the clipboard stack has format |format|.
    295   bool HasFormat(AuraClipboardFormat format) const {
    296     const ClipboardData* data = GetData();
    297     if (!data)
    298       return false;
    299 
    300     return data->format() & format;
    301   }
    302 
    303   void AddToListEnsuringSize(ClipboardData* data) {
    304     DCHECK(data);
    305     data_list_.push_front(data);
    306 
    307     // If the size of list becomes more than the maximum allowed, we delete the
    308     // last element.
    309     if (data_list_.size() > kMaxClipboardSize) {
    310       ClipboardData* last = data_list_.back();
    311       data_list_.pop_back();
    312       delete last;
    313     }
    314   }
    315 
    316   // Stack containing various versions of ClipboardData.
    317   std::list<ClipboardData*> data_list_;
    318 
    319   DISALLOW_COPY_AND_ASSIGN(AuraClipboard);
    320 };
    321 
    322 AuraClipboard* aura_clipboard = NULL;
    323 
    324 AuraClipboard* GetClipboard() {
    325   if (!aura_clipboard)
    326     aura_clipboard = new AuraClipboard();
    327   return aura_clipboard;
    328 }
    329 
    330 void DeleteClipboard() {
    331   if (aura_clipboard)
    332     delete aura_clipboard;
    333   aura_clipboard = NULL;
    334 }
    335 
    336 // Helper class to build a ClipboardData object and write it to clipboard.
    337 class ClipboardDataBuilder {
    338  public:
    339   static void CommitToClipboard() {
    340     GetClipboard()->WriteData(GetCurrentData());
    341     current_data_ = NULL;
    342   }
    343 
    344   static void WriteText(const char* text_data, size_t text_len) {
    345     ClipboardData* data = GetCurrentData();
    346     data->set_text(std::string(text_data, text_len));
    347   }
    348 
    349   static void WriteHTML(const char* markup_data,
    350                         size_t markup_len,
    351                         const char* url_data,
    352                         size_t url_len) {
    353     ClipboardData* data = GetCurrentData();
    354     data->set_markup_data(std::string(markup_data, markup_len));
    355     data->set_url(std::string(url_data, url_len));
    356   }
    357 
    358   static void WriteRTF(const char* rtf_data, size_t rtf_len) {
    359     ClipboardData* data = GetCurrentData();
    360     data->SetRTFData(std::string(rtf_data, rtf_len));
    361   }
    362 
    363   static void WriteBookmark(const char* title_data,
    364                             size_t title_len,
    365                             const char* url_data,
    366                             size_t url_len) {
    367     ClipboardData* data = GetCurrentData();
    368     data->set_bookmark_title(std::string(title_data, title_len));
    369     data->set_bookmark_url(std::string(url_data, url_len));
    370   }
    371 
    372   static void WriteWebSmartPaste() {
    373     ClipboardData* data = GetCurrentData();
    374     data->set_web_smart_paste(true);
    375   }
    376 
    377   static void WriteBitmap(const SkBitmap& bitmap) {
    378     ClipboardData* data = GetCurrentData();
    379     data->SetBitmapData(bitmap);
    380   }
    381 
    382   static void WriteData(const std::string& format,
    383                         const char* data_data,
    384                         size_t data_len) {
    385     ClipboardData* data = GetCurrentData();
    386     data->SetCustomData(format, std::string(data_data, data_len));
    387   }
    388 
    389  private:
    390   static ClipboardData* GetCurrentData() {
    391     if (!current_data_)
    392       current_data_ = new ClipboardData;
    393     return current_data_;
    394   }
    395 
    396   static ClipboardData* current_data_;
    397 };
    398 
    399 ClipboardData* ClipboardDataBuilder::current_data_ = NULL;
    400 
    401 }  // namespace
    402 
    403 Clipboard::FormatType::FormatType() {
    404 }
    405 
    406 Clipboard::FormatType::FormatType(const std::string& native_format)
    407     : data_(native_format) {
    408 }
    409 
    410 Clipboard::FormatType::~FormatType() {
    411 }
    412 
    413 std::string Clipboard::FormatType::Serialize() const {
    414   return data_;
    415 }
    416 
    417 // static
    418 Clipboard::FormatType Clipboard::FormatType::Deserialize(
    419     const std::string& serialization) {
    420   return FormatType(serialization);
    421 }
    422 
    423 bool Clipboard::FormatType::operator<(const FormatType& other) const {
    424   return data_ < other.data_;
    425 }
    426 
    427 bool Clipboard::FormatType::Equals(const FormatType& other) const {
    428   return data_ == other.data_;
    429 }
    430 
    431 Clipboard::Clipboard() {
    432   DCHECK(CalledOnValidThread());
    433   // Make sure clipboard is created.
    434   GetClipboard();
    435 }
    436 
    437 Clipboard::~Clipboard() {
    438   DCHECK(CalledOnValidThread());
    439   DeleteClipboard();
    440 }
    441 
    442 void Clipboard::WriteObjects(ClipboardType type, const ObjectMap& objects) {
    443   DCHECK(CalledOnValidThread());
    444   DCHECK(IsSupportedClipboardType(type));
    445   for (ObjectMap::const_iterator iter = objects.begin();
    446        iter != objects.end(); ++iter) {
    447     DispatchObject(static_cast<ObjectType>(iter->first), iter->second);
    448   }
    449   ClipboardDataBuilder::CommitToClipboard();
    450 }
    451 
    452 bool Clipboard::IsFormatAvailable(const FormatType& format,
    453                                   ClipboardType type) const {
    454   DCHECK(CalledOnValidThread());
    455   DCHECK(IsSupportedClipboardType(type));
    456   AuraClipboard* clipboard = GetClipboard();
    457   if (GetPlainTextFormatType().Equals(format) ||
    458       GetUrlFormatType().Equals(format))
    459     return clipboard->IsFormatAvailable(TEXT);
    460   else if (GetHtmlFormatType().Equals(format))
    461     return clipboard->IsFormatAvailable(HTML);
    462   else if (GetRtfFormatType().Equals(format))
    463     return clipboard->IsFormatAvailable(RTF);
    464   else if (GetBitmapFormatType().Equals(format))
    465     return clipboard->IsFormatAvailable(BITMAP);
    466   else if (GetWebKitSmartPasteFormatType().Equals(format))
    467     return clipboard->IsFormatAvailable(WEB);
    468   else {
    469     const ClipboardData* data = clipboard->GetData();
    470     if (data && data->custom_data_format() == format.ToString())
    471       return true;
    472   }
    473   return false;
    474 }
    475 
    476 void Clipboard::Clear(ClipboardType type) {
    477   DCHECK(CalledOnValidThread());
    478   DCHECK(IsSupportedClipboardType(type));
    479   AuraClipboard* clipboard = GetClipboard();
    480   clipboard->Clear();
    481 }
    482 
    483 void Clipboard::ReadAvailableTypes(ClipboardType type,
    484                                    std::vector<string16>* types,
    485                                    bool* contains_filenames) const {
    486   DCHECK(CalledOnValidThread());
    487   if (!types || !contains_filenames) {
    488     NOTREACHED();
    489     return;
    490   }
    491 
    492   types->clear();
    493   *contains_filenames = false;
    494   if (IsFormatAvailable(GetPlainTextFormatType(), type))
    495     types->push_back(UTF8ToUTF16(GetPlainTextFormatType().ToString()));
    496   if (IsFormatAvailable(GetHtmlFormatType(), type))
    497     types->push_back(UTF8ToUTF16(GetHtmlFormatType().ToString()));
    498   if (IsFormatAvailable(GetRtfFormatType(), type))
    499     types->push_back(UTF8ToUTF16(GetRtfFormatType().ToString()));
    500   if (IsFormatAvailable(GetBitmapFormatType(), type))
    501     types->push_back(UTF8ToUTF16(kMimeTypePNG));
    502 
    503   AuraClipboard* clipboard = GetClipboard();
    504   if (clipboard->IsFormatAvailable(CUSTOM) && clipboard->GetData()) {
    505     ui::ReadCustomDataTypes(clipboard->GetData()->custom_data_data().c_str(),
    506         clipboard->GetData()->custom_data_data().size(), types);
    507   }
    508 }
    509 
    510 void Clipboard::ReadText(ClipboardType type, string16* result) const {
    511   DCHECK(CalledOnValidThread());
    512   GetClipboard()->ReadText(result);
    513 }
    514 
    515 void Clipboard::ReadAsciiText(ClipboardType type, std::string* result) const {
    516   DCHECK(CalledOnValidThread());
    517   GetClipboard()->ReadAsciiText(result);
    518 }
    519 
    520 void Clipboard::ReadHTML(ClipboardType type,
    521                          string16* markup,
    522                          std::string* src_url,
    523                          uint32* fragment_start,
    524                          uint32* fragment_end) const {
    525   DCHECK(CalledOnValidThread());
    526   GetClipboard()->ReadHTML(markup, src_url, fragment_start, fragment_end);
    527 }
    528 
    529 void Clipboard::ReadRTF(ClipboardType type, std::string* result) const {
    530   DCHECK(CalledOnValidThread());
    531   GetClipboard()->ReadRTF(result);
    532 }
    533 
    534 SkBitmap Clipboard::ReadImage(ClipboardType type) const {
    535   DCHECK(CalledOnValidThread());
    536   return GetClipboard()->ReadImage();
    537 }
    538 
    539 void Clipboard::ReadCustomData(ClipboardType clipboard_type,
    540                                const string16& type,
    541                                string16* result) const {
    542   DCHECK(CalledOnValidThread());
    543   GetClipboard()->ReadCustomData(type, result);
    544 }
    545 
    546 void Clipboard::ReadBookmark(string16* title, std::string* url) const {
    547   DCHECK(CalledOnValidThread());
    548   GetClipboard()->ReadBookmark(title, url);
    549 }
    550 
    551 void Clipboard::ReadData(const FormatType& format, std::string* result) const {
    552   DCHECK(CalledOnValidThread());
    553   GetClipboard()->ReadData(format.ToString(), result);
    554 }
    555 
    556 uint64 Clipboard::GetSequenceNumber(ClipboardType type) {
    557   DCHECK(CalledOnValidThread());
    558   return GetClipboard()->GetNumClipboardEntries();
    559 }
    560 
    561 void Clipboard::WriteText(const char* text_data, size_t text_len) {
    562   ClipboardDataBuilder::WriteText(text_data, text_len);
    563 }
    564 
    565 void Clipboard::WriteHTML(const char* markup_data,
    566                           size_t markup_len,
    567                           const char* url_data,
    568                           size_t url_len) {
    569   ClipboardDataBuilder::WriteHTML(markup_data, markup_len, url_data, url_len);
    570 }
    571 
    572 void Clipboard::WriteRTF(const char* rtf_data, size_t data_len) {
    573   ClipboardDataBuilder::WriteRTF(rtf_data, data_len);
    574 }
    575 
    576 void Clipboard::WriteBookmark(const char* title_data,
    577                               size_t title_len,
    578                               const char* url_data,
    579                               size_t url_len) {
    580   ClipboardDataBuilder::WriteBookmark(title_data, title_len, url_data, url_len);
    581 }
    582 
    583 void Clipboard::WriteWebSmartPaste() {
    584   ClipboardDataBuilder::WriteWebSmartPaste();
    585 }
    586 
    587 void Clipboard::WriteBitmap(const SkBitmap& bitmap) {
    588   ClipboardDataBuilder::WriteBitmap(bitmap);
    589 }
    590 
    591 void Clipboard::WriteData(const FormatType& format,
    592                           const char* data_data,
    593                           size_t data_len) {
    594   ClipboardDataBuilder::WriteData(format.ToString(), data_data, data_len);
    595 }
    596 
    597 // static
    598 Clipboard::FormatType Clipboard::GetFormatType(
    599     const std::string& format_string) {
    600   return FormatType::Deserialize(format_string);
    601 }
    602 
    603 // static
    604 const Clipboard::FormatType& Clipboard::GetUrlFormatType() {
    605   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeURIList));
    606   return type;
    607 }
    608 
    609 // static
    610 const Clipboard::FormatType& Clipboard::GetUrlWFormatType() {
    611   return GetUrlFormatType();
    612 }
    613 
    614 // static
    615 const Clipboard::FormatType& Clipboard::GetPlainTextFormatType() {
    616   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeText));
    617   return type;
    618 }
    619 
    620 // static
    621 const Clipboard::FormatType& Clipboard::GetPlainTextWFormatType() {
    622   return GetPlainTextFormatType();
    623 }
    624 
    625 // static
    626 const Clipboard::FormatType& Clipboard::GetFilenameFormatType() {
    627   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeFilename));
    628   return type;
    629 }
    630 
    631 // static
    632 const Clipboard::FormatType& Clipboard::GetFilenameWFormatType() {
    633   return Clipboard::GetFilenameFormatType();
    634 }
    635 
    636 // static
    637 const Clipboard::FormatType& Clipboard::GetHtmlFormatType() {
    638   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeHTML));
    639   return type;
    640 }
    641 
    642 // static
    643 const Clipboard::FormatType& Clipboard::GetRtfFormatType() {
    644   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeRTF));
    645   return type;
    646 }
    647 
    648 // static
    649 const Clipboard::FormatType& Clipboard::GetBitmapFormatType() {
    650   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeBitmap));
    651   return type;
    652 }
    653 
    654 // static
    655 const Clipboard::FormatType& Clipboard::GetWebKitSmartPasteFormatType() {
    656   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeWebkitSmartPaste));
    657   return type;
    658 }
    659 
    660 // static
    661 const Clipboard::FormatType& Clipboard::GetWebCustomDataFormatType() {
    662   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeWebCustomData));
    663   return type;
    664 }
    665 
    666 // static
    667 const Clipboard::FormatType& Clipboard::GetPepperCustomDataFormatType() {
    668   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypePepperCustomData));
    669   return type;
    670 }
    671 
    672 }  // namespace ui
    673