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   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_);
     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() : sequence_number_(0) {
    154   }
    155 
    156   ~AuraClipboard() {
    157     Clear();
    158   }
    159 
    160   void Clear() {
    161     sequence_number_++;
    162     STLDeleteContainerPointers(data_list_.begin(), data_list_.end());
    163     data_list_.clear();
    164   }
    165 
    166   uint64_t sequence_number() const {
    167     return sequence_number_;
    168   }
    169 
    170   // Returns the data currently on the top of the clipboard stack, NULL if the
    171   // clipboard stack is empty.
    172   const ClipboardData* GetData() const {
    173     if (data_list_.empty())
    174       return NULL;
    175     return data_list_.front();
    176   }
    177 
    178   // Returns true if the data on top of the clipboard stack has format |format|
    179   // or another format that can be converted to |format|.
    180   bool IsFormatAvailable(AuraClipboardFormat format) const {
    181     switch (format) {
    182       case TEXT:
    183         return HasFormat(TEXT) || HasFormat(BOOKMARK);
    184       default:
    185         return HasFormat(format);
    186     }
    187   }
    188 
    189   // Reads text from the data at the top of clipboard stack.
    190   void ReadText(base::string16* result) const {
    191     std::string utf8_result;
    192     ReadAsciiText(&utf8_result);
    193     *result = base::UTF8ToUTF16(utf8_result);
    194   }
    195 
    196   // Reads ascii text from the data at the top of clipboard stack.
    197   void ReadAsciiText(std::string* result) const {
    198     result->clear();
    199     const ClipboardData* data = GetData();
    200     if (!data)
    201       return;
    202     if (HasFormat(TEXT))
    203       *result = data->text();
    204     else if (HasFormat(HTML))
    205       *result = data->markup_data();
    206     else if (HasFormat(BOOKMARK))
    207       *result = data->bookmark_url();
    208   }
    209 
    210   // Reads HTML from the data at the top of clipboard stack.
    211   void ReadHTML(base::string16* markup,
    212                 std::string* src_url,
    213                 uint32* fragment_start,
    214                 uint32* fragment_end) const {
    215     markup->clear();
    216     if (src_url)
    217       src_url->clear();
    218     *fragment_start = 0;
    219     *fragment_end = 0;
    220 
    221     if (!HasFormat(HTML))
    222       return;
    223 
    224     const ClipboardData* data = GetData();
    225     *markup = base::UTF8ToUTF16(data->markup_data());
    226     *src_url = data->url();
    227 
    228     *fragment_start = 0;
    229     DCHECK_LE(markup->length(), kuint32max);
    230     *fragment_end = static_cast<uint32>(markup->length());
    231   }
    232 
    233   // Reads RTF from the data at the top of clipboard stack.
    234   void ReadRTF(std::string* result) const {
    235     result->clear();
    236     const ClipboardData* data = GetData();
    237     if (!HasFormat(RTF))
    238       return;
    239 
    240     *result = data->rtf_data();
    241   }
    242 
    243   // Reads image from the data at the top of clipboard stack.
    244   SkBitmap ReadImage() const {
    245     SkBitmap img;
    246     if (!HasFormat(BITMAP))
    247       return img;
    248 
    249     // A shallow copy should be fine here, but just to be safe...
    250     const SkBitmap& clipboard_bitmap = GetData()->bitmap();
    251     clipboard_bitmap.copyTo(&img);
    252     return img;
    253   }
    254 
    255   // Reads data of type |type| from the data at the top of clipboard stack.
    256   void ReadCustomData(const base::string16& type,
    257                       base::string16* result) const {
    258     result->clear();
    259     const ClipboardData* data = GetData();
    260     if (!HasFormat(CUSTOM))
    261       return;
    262 
    263     ui::ReadCustomDataForType(data->custom_data_data().c_str(),
    264         data->custom_data_data().size(),
    265         type, result);
    266   }
    267 
    268   // Reads bookmark from the data at the top of clipboard stack.
    269   void ReadBookmark(base::string16* title, std::string* url) const {
    270     title->clear();
    271     url->clear();
    272     if (!HasFormat(BOOKMARK))
    273       return;
    274 
    275     const ClipboardData* data = GetData();
    276     *title = base::UTF8ToUTF16(data->bookmark_title());
    277     *url = data->bookmark_url();
    278   }
    279 
    280   void ReadData(const std::string& type, std::string* result) const {
    281     result->clear();
    282     const ClipboardData* data = GetData();
    283     if (!HasFormat(CUSTOM) || type != data->custom_data_format())
    284       return;
    285 
    286     *result = data->custom_data_data();
    287   }
    288 
    289   // Writes |data| to the top of the clipboard stack.
    290   void WriteData(ClipboardData* data) {
    291     DCHECK(data);
    292     AddToListEnsuringSize(data);
    293   }
    294 
    295  private:
    296   // True if the data on top of the clipboard stack has format |format|.
    297   bool HasFormat(AuraClipboardFormat format) const {
    298     const ClipboardData* data = GetData();
    299     if (!data)
    300       return false;
    301 
    302     return data->format() & format;
    303   }
    304 
    305   void AddToListEnsuringSize(ClipboardData* data) {
    306     DCHECK(data);
    307     sequence_number_++;
    308     data_list_.push_front(data);
    309 
    310     // If the size of list becomes more than the maximum allowed, we delete the
    311     // last element.
    312     if (data_list_.size() > kMaxClipboardSize) {
    313       ClipboardData* last = data_list_.back();
    314       data_list_.pop_back();
    315       delete last;
    316     }
    317   }
    318 
    319   // Stack containing various versions of ClipboardData.
    320   std::list<ClipboardData*> data_list_;
    321 
    322   // Sequence number uniquely identifying clipboard state.
    323   uint64_t sequence_number_;
    324 
    325   DISALLOW_COPY_AND_ASSIGN(AuraClipboard);
    326 };
    327 
    328 AuraClipboard* aura_clipboard = NULL;
    329 
    330 AuraClipboard* GetClipboard() {
    331   if (!aura_clipboard)
    332     aura_clipboard = new AuraClipboard();
    333   return aura_clipboard;
    334 }
    335 
    336 void DeleteClipboard() {
    337   if (aura_clipboard)
    338     delete aura_clipboard;
    339   aura_clipboard = NULL;
    340 }
    341 
    342 // Helper class to build a ClipboardData object and write it to clipboard.
    343 class ClipboardDataBuilder {
    344  public:
    345   static void CommitToClipboard() {
    346     GetClipboard()->WriteData(GetCurrentData());
    347     current_data_ = NULL;
    348   }
    349 
    350   static void WriteText(const char* text_data, size_t text_len) {
    351     ClipboardData* data = GetCurrentData();
    352     data->set_text(std::string(text_data, text_len));
    353   }
    354 
    355   static void WriteHTML(const char* markup_data,
    356                         size_t markup_len,
    357                         const char* url_data,
    358                         size_t url_len) {
    359     ClipboardData* data = GetCurrentData();
    360     data->set_markup_data(std::string(markup_data, markup_len));
    361     data->set_url(std::string(url_data, url_len));
    362   }
    363 
    364   static void WriteRTF(const char* rtf_data, size_t rtf_len) {
    365     ClipboardData* data = GetCurrentData();
    366     data->SetRTFData(std::string(rtf_data, rtf_len));
    367   }
    368 
    369   static void WriteBookmark(const char* title_data,
    370                             size_t title_len,
    371                             const char* url_data,
    372                             size_t url_len) {
    373     ClipboardData* data = GetCurrentData();
    374     data->set_bookmark_title(std::string(title_data, title_len));
    375     data->set_bookmark_url(std::string(url_data, url_len));
    376   }
    377 
    378   static void WriteWebSmartPaste() {
    379     ClipboardData* data = GetCurrentData();
    380     data->set_web_smart_paste(true);
    381   }
    382 
    383   static void WriteBitmap(const SkBitmap& bitmap) {
    384     ClipboardData* data = GetCurrentData();
    385     data->SetBitmapData(bitmap);
    386   }
    387 
    388   static void WriteData(const std::string& format,
    389                         const char* data_data,
    390                         size_t data_len) {
    391     ClipboardData* data = GetCurrentData();
    392     data->SetCustomData(format, std::string(data_data, data_len));
    393   }
    394 
    395  private:
    396   static ClipboardData* GetCurrentData() {
    397     if (!current_data_)
    398       current_data_ = new ClipboardData;
    399     return current_data_;
    400   }
    401 
    402   static ClipboardData* current_data_;
    403 };
    404 
    405 ClipboardData* ClipboardDataBuilder::current_data_ = NULL;
    406 
    407 }  // namespace
    408 
    409 Clipboard::FormatType::FormatType() {
    410 }
    411 
    412 Clipboard::FormatType::FormatType(const std::string& native_format)
    413     : data_(native_format) {
    414 }
    415 
    416 Clipboard::FormatType::~FormatType() {
    417 }
    418 
    419 std::string Clipboard::FormatType::Serialize() const {
    420   return data_;
    421 }
    422 
    423 // static
    424 Clipboard::FormatType Clipboard::FormatType::Deserialize(
    425     const std::string& serialization) {
    426   return FormatType(serialization);
    427 }
    428 
    429 bool Clipboard::FormatType::operator<(const FormatType& other) const {
    430   return data_ < other.data_;
    431 }
    432 
    433 bool Clipboard::FormatType::Equals(const FormatType& other) const {
    434   return data_ == other.data_;
    435 }
    436 
    437 Clipboard::Clipboard() {
    438   DCHECK(CalledOnValidThread());
    439   // Make sure clipboard is created.
    440   GetClipboard();
    441 }
    442 
    443 Clipboard::~Clipboard() {
    444   DCHECK(CalledOnValidThread());
    445   DeleteClipboard();
    446 }
    447 
    448 void Clipboard::WriteObjects(ClipboardType type, const ObjectMap& objects) {
    449   DCHECK(CalledOnValidThread());
    450   DCHECK(IsSupportedClipboardType(type));
    451   for (ObjectMap::const_iterator iter = objects.begin();
    452        iter != objects.end(); ++iter) {
    453     DispatchObject(static_cast<ObjectType>(iter->first), iter->second);
    454   }
    455   ClipboardDataBuilder::CommitToClipboard();
    456 }
    457 
    458 bool Clipboard::IsFormatAvailable(const FormatType& format,
    459                                   ClipboardType type) const {
    460   DCHECK(CalledOnValidThread());
    461   DCHECK(IsSupportedClipboardType(type));
    462   AuraClipboard* clipboard = GetClipboard();
    463   if (GetPlainTextFormatType().Equals(format) ||
    464       GetUrlFormatType().Equals(format))
    465     return clipboard->IsFormatAvailable(TEXT);
    466   else if (GetHtmlFormatType().Equals(format))
    467     return clipboard->IsFormatAvailable(HTML);
    468   else if (GetRtfFormatType().Equals(format))
    469     return clipboard->IsFormatAvailable(RTF);
    470   else if (GetBitmapFormatType().Equals(format))
    471     return clipboard->IsFormatAvailable(BITMAP);
    472   else if (GetWebKitSmartPasteFormatType().Equals(format))
    473     return clipboard->IsFormatAvailable(WEB);
    474   else {
    475     const ClipboardData* data = clipboard->GetData();
    476     if (data && data->custom_data_format() == format.ToString())
    477       return true;
    478   }
    479   return false;
    480 }
    481 
    482 void Clipboard::Clear(ClipboardType type) {
    483   DCHECK(CalledOnValidThread());
    484   DCHECK(IsSupportedClipboardType(type));
    485   AuraClipboard* clipboard = GetClipboard();
    486   clipboard->Clear();
    487 }
    488 
    489 void Clipboard::ReadAvailableTypes(ClipboardType type,
    490                                    std::vector<base::string16>* types,
    491                                    bool* contains_filenames) const {
    492   DCHECK(CalledOnValidThread());
    493   if (!types || !contains_filenames) {
    494     NOTREACHED();
    495     return;
    496   }
    497 
    498   types->clear();
    499   *contains_filenames = false;
    500   if (IsFormatAvailable(GetPlainTextFormatType(), type))
    501     types->push_back(base::UTF8ToUTF16(GetPlainTextFormatType().ToString()));
    502   if (IsFormatAvailable(GetHtmlFormatType(), type))
    503     types->push_back(base::UTF8ToUTF16(GetHtmlFormatType().ToString()));
    504   if (IsFormatAvailable(GetRtfFormatType(), type))
    505     types->push_back(base::UTF8ToUTF16(GetRtfFormatType().ToString()));
    506   if (IsFormatAvailable(GetBitmapFormatType(), type))
    507     types->push_back(base::UTF8ToUTF16(kMimeTypePNG));
    508 
    509   AuraClipboard* clipboard = GetClipboard();
    510   if (clipboard->IsFormatAvailable(CUSTOM) && clipboard->GetData()) {
    511     ui::ReadCustomDataTypes(clipboard->GetData()->custom_data_data().c_str(),
    512         clipboard->GetData()->custom_data_data().size(), types);
    513   }
    514 }
    515 
    516 void Clipboard::ReadText(ClipboardType type, base::string16* result) const {
    517   DCHECK(CalledOnValidThread());
    518   GetClipboard()->ReadText(result);
    519 }
    520 
    521 void Clipboard::ReadAsciiText(ClipboardType type, std::string* result) const {
    522   DCHECK(CalledOnValidThread());
    523   GetClipboard()->ReadAsciiText(result);
    524 }
    525 
    526 void Clipboard::ReadHTML(ClipboardType type,
    527                          base::string16* markup,
    528                          std::string* src_url,
    529                          uint32* fragment_start,
    530                          uint32* fragment_end) const {
    531   DCHECK(CalledOnValidThread());
    532   GetClipboard()->ReadHTML(markup, src_url, fragment_start, fragment_end);
    533 }
    534 
    535 void Clipboard::ReadRTF(ClipboardType type, std::string* result) const {
    536   DCHECK(CalledOnValidThread());
    537   GetClipboard()->ReadRTF(result);
    538 }
    539 
    540 SkBitmap Clipboard::ReadImage(ClipboardType type) const {
    541   DCHECK(CalledOnValidThread());
    542   return GetClipboard()->ReadImage();
    543 }
    544 
    545 void Clipboard::ReadCustomData(ClipboardType clipboard_type,
    546                                const base::string16& type,
    547                                base::string16* result) const {
    548   DCHECK(CalledOnValidThread());
    549   GetClipboard()->ReadCustomData(type, result);
    550 }
    551 
    552 void Clipboard::ReadBookmark(base::string16* title, std::string* url) const {
    553   DCHECK(CalledOnValidThread());
    554   GetClipboard()->ReadBookmark(title, url);
    555 }
    556 
    557 void Clipboard::ReadData(const FormatType& format, std::string* result) const {
    558   DCHECK(CalledOnValidThread());
    559   GetClipboard()->ReadData(format.ToString(), result);
    560 }
    561 
    562 uint64 Clipboard::GetSequenceNumber(ClipboardType type) {
    563   DCHECK(CalledOnValidThread());
    564   return GetClipboard()->sequence_number();
    565 }
    566 
    567 void Clipboard::WriteText(const char* text_data, size_t text_len) {
    568   ClipboardDataBuilder::WriteText(text_data, text_len);
    569 }
    570 
    571 void Clipboard::WriteHTML(const char* markup_data,
    572                           size_t markup_len,
    573                           const char* url_data,
    574                           size_t url_len) {
    575   ClipboardDataBuilder::WriteHTML(markup_data, markup_len, url_data, url_len);
    576 }
    577 
    578 void Clipboard::WriteRTF(const char* rtf_data, size_t data_len) {
    579   ClipboardDataBuilder::WriteRTF(rtf_data, data_len);
    580 }
    581 
    582 void Clipboard::WriteBookmark(const char* title_data,
    583                               size_t title_len,
    584                               const char* url_data,
    585                               size_t url_len) {
    586   ClipboardDataBuilder::WriteBookmark(title_data, title_len, url_data, url_len);
    587 }
    588 
    589 void Clipboard::WriteWebSmartPaste() {
    590   ClipboardDataBuilder::WriteWebSmartPaste();
    591 }
    592 
    593 void Clipboard::WriteBitmap(const SkBitmap& bitmap) {
    594   ClipboardDataBuilder::WriteBitmap(bitmap);
    595 }
    596 
    597 void Clipboard::WriteData(const FormatType& format,
    598                           const char* data_data,
    599                           size_t data_len) {
    600   ClipboardDataBuilder::WriteData(format.ToString(), data_data, data_len);
    601 }
    602 
    603 // static
    604 Clipboard::FormatType Clipboard::GetFormatType(
    605     const std::string& format_string) {
    606   return FormatType::Deserialize(format_string);
    607 }
    608 
    609 // static
    610 const Clipboard::FormatType& Clipboard::GetUrlFormatType() {
    611   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeURIList));
    612   return type;
    613 }
    614 
    615 // static
    616 const Clipboard::FormatType& Clipboard::GetUrlWFormatType() {
    617   return GetUrlFormatType();
    618 }
    619 
    620 // static
    621 const Clipboard::FormatType& Clipboard::GetPlainTextFormatType() {
    622   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeText));
    623   return type;
    624 }
    625 
    626 // static
    627 const Clipboard::FormatType& Clipboard::GetPlainTextWFormatType() {
    628   return GetPlainTextFormatType();
    629 }
    630 
    631 // static
    632 const Clipboard::FormatType& Clipboard::GetFilenameFormatType() {
    633   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeFilename));
    634   return type;
    635 }
    636 
    637 // static
    638 const Clipboard::FormatType& Clipboard::GetFilenameWFormatType() {
    639   return Clipboard::GetFilenameFormatType();
    640 }
    641 
    642 // static
    643 const Clipboard::FormatType& Clipboard::GetHtmlFormatType() {
    644   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeHTML));
    645   return type;
    646 }
    647 
    648 // static
    649 const Clipboard::FormatType& Clipboard::GetRtfFormatType() {
    650   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeRTF));
    651   return type;
    652 }
    653 
    654 // static
    655 const Clipboard::FormatType& Clipboard::GetBitmapFormatType() {
    656   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeBitmap));
    657   return type;
    658 }
    659 
    660 // static
    661 const Clipboard::FormatType& Clipboard::GetWebKitSmartPasteFormatType() {
    662   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeWebkitSmartPaste));
    663   return type;
    664 }
    665 
    666 // static
    667 const Clipboard::FormatType& Clipboard::GetWebCustomDataFormatType() {
    668   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeWebCustomData));
    669   return type;
    670 }
    671 
    672 // static
    673 const Clipboard::FormatType& Clipboard::GetPepperCustomDataFormatType() {
    674   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypePepperCustomData));
    675   return type;
    676 }
    677 
    678 }  // namespace ui
    679