root/ui/base/clipboard/clipboard_aura.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. format_
  2. format
  3. text
  4. set_text
  5. markup_data
  6. set_markup_data
  7. rtf_data
  8. SetRTFData
  9. url
  10. set_url
  11. bookmark_title
  12. set_bookmark_title
  13. bookmark_url
  14. set_bookmark_url
  15. bitmap
  16. SetBitmapData
  17. custom_data_format
  18. custom_data_data
  19. SetCustomData
  20. web_smart_paste
  21. set_web_smart_paste
  22. Clear
  23. sequence_number
  24. GetData
  25. IsFormatAvailable
  26. ReadText
  27. ReadAsciiText
  28. ReadHTML
  29. ReadRTF
  30. ReadImage
  31. ReadCustomData
  32. ReadBookmark
  33. ReadData
  34. WriteData
  35. HasFormat
  36. AddToListEnsuringSize
  37. GetClipboard
  38. DeleteClipboard
  39. CommitToClipboard
  40. WriteText
  41. WriteHTML
  42. WriteRTF
  43. WriteBookmark
  44. WriteWebSmartPaste
  45. WriteBitmap
  46. WriteData
  47. GetCurrentData
  48. Serialize
  49. Deserialize
  50. Equals
  51. WriteObjects
  52. IsFormatAvailable
  53. Clear
  54. ReadAvailableTypes
  55. ReadText
  56. ReadAsciiText
  57. ReadHTML
  58. ReadRTF
  59. ReadImage
  60. ReadCustomData
  61. ReadBookmark
  62. ReadData
  63. GetSequenceNumber
  64. WriteText
  65. WriteHTML
  66. WriteRTF
  67. WriteBookmark
  68. WriteWebSmartPaste
  69. WriteBitmap
  70. WriteData
  71. GetFormatType
  72. GetUrlFormatType
  73. GetUrlWFormatType
  74. GetPlainTextFormatType
  75. GetPlainTextWFormatType
  76. GetFilenameFormatType
  77. GetFilenameWFormatType
  78. GetHtmlFormatType
  79. GetRtfFormatType
  80. GetBitmapFormatType
  81. GetWebKitSmartPasteFormatType
  82. GetWebCustomDataFormatType
  83. GetPepperCustomDataFormatType

// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/base/clipboard/clipboard.h"

#include <list>

#include "base/basictypes.h"
#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/clipboard/custom_data_helper.h"
#include "ui/gfx/size.h"

namespace ui {

namespace {
const char kMimeTypeFilename[] = "chromium/filename";
const char kMimeTypeBitmap[] = "image/bmp";
const char kMimeTypePepperCustomData[] = "chromium/x-pepper-custom-data";
const char kMimeTypeWebkitSmartPaste[] = "chromium/x-webkit-paste";
const size_t kMaxClipboardSize = 1;

// Clipboard data format used by AuraClipboard.
enum AuraClipboardFormat {
  TEXT      = 1 << 0,
  HTML      = 1 << 1,
  RTF       = 1 << 2,
  BOOKMARK  = 1 << 3,
  BITMAP    = 1 << 4,
  CUSTOM    = 1 << 5,
  WEB       = 1 << 6,
};

// ClipboardData contains data copied to the Clipboard for a variety of formats.
// It mostly just provides APIs to cleanly access and manipulate this data.
class ClipboardData {
 public:
  ClipboardData()
      : web_smart_paste_(false),
        format_(0) {}

  virtual ~ClipboardData() {}

  // Bitmask of AuraClipboardFormat types.
  int format() const { return format_; }

  const std::string& text() const { return text_; }
  void set_text(const std::string& text) {
    text_ = text;
    format_ |= TEXT;
  }

  const std::string& markup_data() const { return markup_data_; }
  void set_markup_data(const std::string& markup_data) {
    markup_data_ = markup_data;
    format_ |= HTML;
  }

  const std::string& rtf_data() const { return rtf_data_; }
  void SetRTFData(const std::string& rtf_data) {
    rtf_data_ = rtf_data;
    format_ |= RTF;
  }

  const std::string& url() const { return url_; }
  void set_url(const std::string& url) {
    url_ = url;
    format_ |= HTML;
  }

  const std::string& bookmark_title() const { return bookmark_title_; }
  void set_bookmark_title(const std::string& bookmark_title) {
    bookmark_title_ = bookmark_title;
    format_ |= BOOKMARK;
  }

  const std::string& bookmark_url() const { return bookmark_url_; }
  void set_bookmark_url(const std::string& bookmark_url) {
    bookmark_url_ = bookmark_url;
    format_ |= BOOKMARK;
  }

  const SkBitmap& bitmap() const { return bitmap_; }
  void SetBitmapData(const SkBitmap& bitmap) {
    bitmap.copyTo(&bitmap_);
    format_ |= BITMAP;
  }

  const std::string& custom_data_format() const { return custom_data_format_; }
  const std::string& custom_data_data() const { return custom_data_data_; }
  void SetCustomData(const std::string& data_format,
                     const std::string& data_data) {
    if (data_data.size() == 0) {
      custom_data_data_.clear();
      custom_data_format_.clear();
      return;
    }
    custom_data_data_ = data_data;
    custom_data_format_ = data_format;
    format_ |= CUSTOM;
  }

  bool web_smart_paste() const { return web_smart_paste_; }
  void set_web_smart_paste(bool web_smart_paste) {
    web_smart_paste_ = web_smart_paste;
    format_ |= WEB;
  }

 private:
  // Plain text in UTF8 format.
  std::string text_;

  // HTML markup data in UTF8 format.
  std::string markup_data_;
  std::string url_;

  // RTF data.
  std::string rtf_data_;

  // Bookmark title in UTF8 format.
  std::string bookmark_title_;
  std::string bookmark_url_;

  // Filenames.
  std::vector<std::string> files_;

  // Bitmap images.
  SkBitmap bitmap_;

  // Data with custom format.
  std::string custom_data_format_;
  std::string custom_data_data_;

  // WebKit smart paste data.
  bool web_smart_paste_;

  int format_;

  DISALLOW_COPY_AND_ASSIGN(ClipboardData);
};

// Platform clipboard implementation for Aura. This handles things like format
// conversion, versioning of clipboard items etc. The goal is to roughly provide
// a substitute to platform clipboards on other platforms such as GtkClipboard
// on gtk or winapi clipboard on win.
class AuraClipboard {
 public:
  AuraClipboard() : sequence_number_(0) {
  }

  ~AuraClipboard() {
    Clear();
  }

  void Clear() {
    sequence_number_++;
    STLDeleteContainerPointers(data_list_.begin(), data_list_.end());
    data_list_.clear();
  }

  uint64_t sequence_number() const {
    return sequence_number_;
  }

  // Returns the data currently on the top of the clipboard stack, NULL if the
  // clipboard stack is empty.
  const ClipboardData* GetData() const {
    if (data_list_.empty())
      return NULL;
    return data_list_.front();
  }

  // Returns true if the data on top of the clipboard stack has format |format|
  // or another format that can be converted to |format|.
  bool IsFormatAvailable(AuraClipboardFormat format) const {
    switch (format) {
      case TEXT:
        return HasFormat(TEXT) || HasFormat(BOOKMARK);
      default:
        return HasFormat(format);
    }
  }

  // Reads text from the data at the top of clipboard stack.
  void ReadText(base::string16* result) const {
    std::string utf8_result;
    ReadAsciiText(&utf8_result);
    *result = base::UTF8ToUTF16(utf8_result);
  }

  // Reads ascii text from the data at the top of clipboard stack.
  void ReadAsciiText(std::string* result) const {
    result->clear();
    const ClipboardData* data = GetData();
    if (!data)
      return;
    if (HasFormat(TEXT))
      *result = data->text();
    else if (HasFormat(HTML))
      *result = data->markup_data();
    else if (HasFormat(BOOKMARK))
      *result = data->bookmark_url();
  }

  // Reads HTML from the data at the top of clipboard stack.
  void ReadHTML(base::string16* markup,
                std::string* src_url,
                uint32* fragment_start,
                uint32* fragment_end) const {
    markup->clear();
    if (src_url)
      src_url->clear();
    *fragment_start = 0;
    *fragment_end = 0;

    if (!HasFormat(HTML))
      return;

    const ClipboardData* data = GetData();
    *markup = base::UTF8ToUTF16(data->markup_data());
    *src_url = data->url();

    *fragment_start = 0;
    DCHECK_LE(markup->length(), kuint32max);
    *fragment_end = static_cast<uint32>(markup->length());
  }

  // Reads RTF from the data at the top of clipboard stack.
  void ReadRTF(std::string* result) const {
    result->clear();
    const ClipboardData* data = GetData();
    if (!HasFormat(RTF))
      return;

    *result = data->rtf_data();
  }

  // Reads image from the data at the top of clipboard stack.
  SkBitmap ReadImage() const {
    SkBitmap img;
    if (!HasFormat(BITMAP))
      return img;

    // A shallow copy should be fine here, but just to be safe...
    const SkBitmap& clipboard_bitmap = GetData()->bitmap();
    clipboard_bitmap.copyTo(&img);
    return img;
  }

  // Reads data of type |type| from the data at the top of clipboard stack.
  void ReadCustomData(const base::string16& type,
                      base::string16* result) const {
    result->clear();
    const ClipboardData* data = GetData();
    if (!HasFormat(CUSTOM))
      return;

    ui::ReadCustomDataForType(data->custom_data_data().c_str(),
        data->custom_data_data().size(),
        type, result);
  }

  // Reads bookmark from the data at the top of clipboard stack.
  void ReadBookmark(base::string16* title, std::string* url) const {
    title->clear();
    url->clear();
    if (!HasFormat(BOOKMARK))
      return;

    const ClipboardData* data = GetData();
    *title = base::UTF8ToUTF16(data->bookmark_title());
    *url = data->bookmark_url();
  }

  void ReadData(const std::string& type, std::string* result) const {
    result->clear();
    const ClipboardData* data = GetData();
    if (!HasFormat(CUSTOM) || type != data->custom_data_format())
      return;

    *result = data->custom_data_data();
  }

  // Writes |data| to the top of the clipboard stack.
  void WriteData(ClipboardData* data) {
    DCHECK(data);
    AddToListEnsuringSize(data);
  }

 private:
  // True if the data on top of the clipboard stack has format |format|.
  bool HasFormat(AuraClipboardFormat format) const {
    const ClipboardData* data = GetData();
    if (!data)
      return false;

    return data->format() & format;
  }

  void AddToListEnsuringSize(ClipboardData* data) {
    DCHECK(data);
    sequence_number_++;
    data_list_.push_front(data);

    // If the size of list becomes more than the maximum allowed, we delete the
    // last element.
    if (data_list_.size() > kMaxClipboardSize) {
      ClipboardData* last = data_list_.back();
      data_list_.pop_back();
      delete last;
    }
  }

  // Stack containing various versions of ClipboardData.
  std::list<ClipboardData*> data_list_;

  // Sequence number uniquely identifying clipboard state.
  uint64_t sequence_number_;

  DISALLOW_COPY_AND_ASSIGN(AuraClipboard);
};

AuraClipboard* aura_clipboard = NULL;

AuraClipboard* GetClipboard() {
  if (!aura_clipboard)
    aura_clipboard = new AuraClipboard();
  return aura_clipboard;
}

void DeleteClipboard() {
  if (aura_clipboard)
    delete aura_clipboard;
  aura_clipboard = NULL;
}

// Helper class to build a ClipboardData object and write it to clipboard.
class ClipboardDataBuilder {
 public:
  static void CommitToClipboard() {
    GetClipboard()->WriteData(GetCurrentData());
    current_data_ = NULL;
  }

  static void WriteText(const char* text_data, size_t text_len) {
    ClipboardData* data = GetCurrentData();
    data->set_text(std::string(text_data, text_len));
  }

  static void WriteHTML(const char* markup_data,
                        size_t markup_len,
                        const char* url_data,
                        size_t url_len) {
    ClipboardData* data = GetCurrentData();
    data->set_markup_data(std::string(markup_data, markup_len));
    data->set_url(std::string(url_data, url_len));
  }

  static void WriteRTF(const char* rtf_data, size_t rtf_len) {
    ClipboardData* data = GetCurrentData();
    data->SetRTFData(std::string(rtf_data, rtf_len));
  }

  static void WriteBookmark(const char* title_data,
                            size_t title_len,
                            const char* url_data,
                            size_t url_len) {
    ClipboardData* data = GetCurrentData();
    data->set_bookmark_title(std::string(title_data, title_len));
    data->set_bookmark_url(std::string(url_data, url_len));
  }

  static void WriteWebSmartPaste() {
    ClipboardData* data = GetCurrentData();
    data->set_web_smart_paste(true);
  }

  static void WriteBitmap(const SkBitmap& bitmap) {
    ClipboardData* data = GetCurrentData();
    data->SetBitmapData(bitmap);
  }

  static void WriteData(const std::string& format,
                        const char* data_data,
                        size_t data_len) {
    ClipboardData* data = GetCurrentData();
    data->SetCustomData(format, std::string(data_data, data_len));
  }

 private:
  static ClipboardData* GetCurrentData() {
    if (!current_data_)
      current_data_ = new ClipboardData;
    return current_data_;
  }

  static ClipboardData* current_data_;
};

ClipboardData* ClipboardDataBuilder::current_data_ = NULL;

}  // namespace

Clipboard::FormatType::FormatType() {
}

Clipboard::FormatType::FormatType(const std::string& native_format)
    : data_(native_format) {
}

Clipboard::FormatType::~FormatType() {
}

std::string Clipboard::FormatType::Serialize() const {
  return data_;
}

// static
Clipboard::FormatType Clipboard::FormatType::Deserialize(
    const std::string& serialization) {
  return FormatType(serialization);
}

bool Clipboard::FormatType::operator<(const FormatType& other) const {
  return data_ < other.data_;
}

bool Clipboard::FormatType::Equals(const FormatType& other) const {
  return data_ == other.data_;
}

Clipboard::Clipboard() {
  DCHECK(CalledOnValidThread());
  // Make sure clipboard is created.
  GetClipboard();
}

Clipboard::~Clipboard() {
  DCHECK(CalledOnValidThread());
  DeleteClipboard();
}

void Clipboard::WriteObjects(ClipboardType type, const ObjectMap& objects) {
  DCHECK(CalledOnValidThread());
  DCHECK(IsSupportedClipboardType(type));
  for (ObjectMap::const_iterator iter = objects.begin();
       iter != objects.end(); ++iter) {
    DispatchObject(static_cast<ObjectType>(iter->first), iter->second);
  }
  ClipboardDataBuilder::CommitToClipboard();
}

bool Clipboard::IsFormatAvailable(const FormatType& format,
                                  ClipboardType type) const {
  DCHECK(CalledOnValidThread());
  DCHECK(IsSupportedClipboardType(type));
  AuraClipboard* clipboard = GetClipboard();
  if (GetPlainTextFormatType().Equals(format) ||
      GetUrlFormatType().Equals(format))
    return clipboard->IsFormatAvailable(TEXT);
  else if (GetHtmlFormatType().Equals(format))
    return clipboard->IsFormatAvailable(HTML);
  else if (GetRtfFormatType().Equals(format))
    return clipboard->IsFormatAvailable(RTF);
  else if (GetBitmapFormatType().Equals(format))
    return clipboard->IsFormatAvailable(BITMAP);
  else if (GetWebKitSmartPasteFormatType().Equals(format))
    return clipboard->IsFormatAvailable(WEB);
  else {
    const ClipboardData* data = clipboard->GetData();
    if (data && data->custom_data_format() == format.ToString())
      return true;
  }
  return false;
}

void Clipboard::Clear(ClipboardType type) {
  DCHECK(CalledOnValidThread());
  DCHECK(IsSupportedClipboardType(type));
  AuraClipboard* clipboard = GetClipboard();
  clipboard->Clear();
}

void Clipboard::ReadAvailableTypes(ClipboardType type,
                                   std::vector<base::string16>* types,
                                   bool* contains_filenames) const {
  DCHECK(CalledOnValidThread());
  if (!types || !contains_filenames) {
    NOTREACHED();
    return;
  }

  types->clear();
  *contains_filenames = false;
  if (IsFormatAvailable(GetPlainTextFormatType(), type))
    types->push_back(base::UTF8ToUTF16(GetPlainTextFormatType().ToString()));
  if (IsFormatAvailable(GetHtmlFormatType(), type))
    types->push_back(base::UTF8ToUTF16(GetHtmlFormatType().ToString()));
  if (IsFormatAvailable(GetRtfFormatType(), type))
    types->push_back(base::UTF8ToUTF16(GetRtfFormatType().ToString()));
  if (IsFormatAvailable(GetBitmapFormatType(), type))
    types->push_back(base::UTF8ToUTF16(kMimeTypePNG));

  AuraClipboard* clipboard = GetClipboard();
  if (clipboard->IsFormatAvailable(CUSTOM) && clipboard->GetData()) {
    ui::ReadCustomDataTypes(clipboard->GetData()->custom_data_data().c_str(),
        clipboard->GetData()->custom_data_data().size(), types);
  }
}

void Clipboard::ReadText(ClipboardType type, base::string16* result) const {
  DCHECK(CalledOnValidThread());
  GetClipboard()->ReadText(result);
}

void Clipboard::ReadAsciiText(ClipboardType type, std::string* result) const {
  DCHECK(CalledOnValidThread());
  GetClipboard()->ReadAsciiText(result);
}

void Clipboard::ReadHTML(ClipboardType type,
                         base::string16* markup,
                         std::string* src_url,
                         uint32* fragment_start,
                         uint32* fragment_end) const {
  DCHECK(CalledOnValidThread());
  GetClipboard()->ReadHTML(markup, src_url, fragment_start, fragment_end);
}

void Clipboard::ReadRTF(ClipboardType type, std::string* result) const {
  DCHECK(CalledOnValidThread());
  GetClipboard()->ReadRTF(result);
}

SkBitmap Clipboard::ReadImage(ClipboardType type) const {
  DCHECK(CalledOnValidThread());
  return GetClipboard()->ReadImage();
}

void Clipboard::ReadCustomData(ClipboardType clipboard_type,
                               const base::string16& type,
                               base::string16* result) const {
  DCHECK(CalledOnValidThread());
  GetClipboard()->ReadCustomData(type, result);
}

void Clipboard::ReadBookmark(base::string16* title, std::string* url) const {
  DCHECK(CalledOnValidThread());
  GetClipboard()->ReadBookmark(title, url);
}

void Clipboard::ReadData(const FormatType& format, std::string* result) const {
  DCHECK(CalledOnValidThread());
  GetClipboard()->ReadData(format.ToString(), result);
}

uint64 Clipboard::GetSequenceNumber(ClipboardType type) {
  DCHECK(CalledOnValidThread());
  return GetClipboard()->sequence_number();
}

void Clipboard::WriteText(const char* text_data, size_t text_len) {
  ClipboardDataBuilder::WriteText(text_data, text_len);
}

void Clipboard::WriteHTML(const char* markup_data,
                          size_t markup_len,
                          const char* url_data,
                          size_t url_len) {
  ClipboardDataBuilder::WriteHTML(markup_data, markup_len, url_data, url_len);
}

void Clipboard::WriteRTF(const char* rtf_data, size_t data_len) {
  ClipboardDataBuilder::WriteRTF(rtf_data, data_len);
}

void Clipboard::WriteBookmark(const char* title_data,
                              size_t title_len,
                              const char* url_data,
                              size_t url_len) {
  ClipboardDataBuilder::WriteBookmark(title_data, title_len, url_data, url_len);
}

void Clipboard::WriteWebSmartPaste() {
  ClipboardDataBuilder::WriteWebSmartPaste();
}

void Clipboard::WriteBitmap(const SkBitmap& bitmap) {
  ClipboardDataBuilder::WriteBitmap(bitmap);
}

void Clipboard::WriteData(const FormatType& format,
                          const char* data_data,
                          size_t data_len) {
  ClipboardDataBuilder::WriteData(format.ToString(), data_data, data_len);
}

// static
Clipboard::FormatType Clipboard::GetFormatType(
    const std::string& format_string) {
  return FormatType::Deserialize(format_string);
}

// static
const Clipboard::FormatType& Clipboard::GetUrlFormatType() {
  CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeURIList));
  return type;
}

// static
const Clipboard::FormatType& Clipboard::GetUrlWFormatType() {
  return GetUrlFormatType();
}

// static
const Clipboard::FormatType& Clipboard::GetPlainTextFormatType() {
  CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeText));
  return type;
}

// static
const Clipboard::FormatType& Clipboard::GetPlainTextWFormatType() {
  return GetPlainTextFormatType();
}

// static
const Clipboard::FormatType& Clipboard::GetFilenameFormatType() {
  CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeFilename));
  return type;
}

// static
const Clipboard::FormatType& Clipboard::GetFilenameWFormatType() {
  return Clipboard::GetFilenameFormatType();
}

// static
const Clipboard::FormatType& Clipboard::GetHtmlFormatType() {
  CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeHTML));
  return type;
}

// static
const Clipboard::FormatType& Clipboard::GetRtfFormatType() {
  CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeRTF));
  return type;
}

// static
const Clipboard::FormatType& Clipboard::GetBitmapFormatType() {
  CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeBitmap));
  return type;
}

// static
const Clipboard::FormatType& Clipboard::GetWebKitSmartPasteFormatType() {
  CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeWebkitSmartPaste));
  return type;
}

// static
const Clipboard::FormatType& Clipboard::GetWebCustomDataFormatType() {
  CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeWebCustomData));
  return type;
}

// static
const Clipboard::FormatType& Clipboard::GetPepperCustomDataFormatType() {
  CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypePepperCustomData));
  return type;
}

}  // namespace ui

/* [<][>][^][v][top][bottom][index][help] */