1// Copyright (c) 2013 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 "content/renderer/webclipboard_impl.h"
6
7#include "base/logging.h"
8#include "base/pickle.h"
9#include "base/strings/string_util.h"
10#include "base/strings/utf_string_conversions.h"
11#include "content/common/clipboard_format.h"
12#include "content/public/common/drop_data.h"
13#include "content/renderer/clipboard_utils.h"
14#include "content/renderer/drop_data_builder.h"
15#include "content/renderer/scoped_clipboard_writer_glue.h"
16#include "third_party/WebKit/public/platform/WebData.h"
17#include "third_party/WebKit/public/platform/WebDragData.h"
18#include "third_party/WebKit/public/platform/WebImage.h"
19#include "third_party/WebKit/public/platform/WebSize.h"
20#include "third_party/WebKit/public/platform/WebString.h"
21#include "third_party/WebKit/public/platform/WebURL.h"
22#include "third_party/WebKit/public/platform/WebVector.h"
23#include "third_party/skia/include/core/SkBitmap.h"
24#include "ui/base/clipboard/clipboard.h"
25#include "ui/base/clipboard/custom_data_helper.h"
26#include "url/gurl.h"
27
28using blink::WebClipboard;
29using blink::WebData;
30using blink::WebDragData;
31using blink::WebImage;
32using blink::WebString;
33using blink::WebURL;
34using blink::WebVector;
35
36namespace content {
37
38WebClipboardImpl::WebClipboardImpl(ClipboardClient* client)
39    : client_(client) {
40}
41
42WebClipboardImpl::~WebClipboardImpl() {
43}
44
45uint64 WebClipboardImpl::sequenceNumber(Buffer buffer) {
46  ui::ClipboardType clipboard_type;
47  if (!ConvertBufferType(buffer, &clipboard_type))
48    return 0;
49
50  return client_->GetSequenceNumber(clipboard_type);
51}
52
53bool WebClipboardImpl::isFormatAvailable(Format format, Buffer buffer) {
54  ui::ClipboardType clipboard_type = ui::CLIPBOARD_TYPE_COPY_PASTE;
55
56  if (!ConvertBufferType(buffer, &clipboard_type))
57    return false;
58
59  switch (format) {
60    case FormatPlainText:
61      return client_->IsFormatAvailable(CLIPBOARD_FORMAT_PLAINTEXT,
62                                        clipboard_type);
63    case FormatHTML:
64      return client_->IsFormatAvailable(CLIPBOARD_FORMAT_HTML, clipboard_type);
65    case FormatSmartPaste:
66      return client_->IsFormatAvailable(CLIPBOARD_FORMAT_SMART_PASTE,
67                                        clipboard_type);
68    case FormatBookmark:
69      return client_->IsFormatAvailable(CLIPBOARD_FORMAT_BOOKMARK,
70                                        clipboard_type);
71    default:
72      NOTREACHED();
73  }
74
75  return false;
76}
77
78WebVector<WebString> WebClipboardImpl::readAvailableTypes(
79    Buffer buffer, bool* contains_filenames) {
80  ui::ClipboardType clipboard_type;
81  std::vector<base::string16> types;
82  if (ConvertBufferType(buffer, &clipboard_type)) {
83    client_->ReadAvailableTypes(clipboard_type, &types, contains_filenames);
84  }
85  return types;
86}
87
88WebString WebClipboardImpl::readPlainText(Buffer buffer) {
89  ui::ClipboardType clipboard_type;
90  if (!ConvertBufferType(buffer, &clipboard_type))
91    return WebString();
92
93  base::string16 text;
94  client_->ReadText(clipboard_type, &text);
95  return text;
96}
97
98WebString WebClipboardImpl::readHTML(Buffer buffer, WebURL* source_url,
99                                     unsigned* fragment_start,
100                                     unsigned* fragment_end) {
101  ui::ClipboardType clipboard_type;
102  if (!ConvertBufferType(buffer, &clipboard_type))
103    return WebString();
104
105  base::string16 html_stdstr;
106  GURL gurl;
107  client_->ReadHTML(clipboard_type, &html_stdstr, &gurl,
108                    static_cast<uint32*>(fragment_start),
109                    static_cast<uint32*>(fragment_end));
110  *source_url = gurl;
111  return html_stdstr;
112}
113
114WebData WebClipboardImpl::readImage(Buffer buffer) {
115  ui::ClipboardType clipboard_type;
116  if (!ConvertBufferType(buffer, &clipboard_type))
117    return WebData();
118
119  std::string png_data;
120  client_->ReadImage(clipboard_type, &png_data);
121  return WebData(png_data);
122}
123
124WebString WebClipboardImpl::readCustomData(Buffer buffer,
125                                           const WebString& type) {
126  ui::ClipboardType clipboard_type;
127  if (!ConvertBufferType(buffer, &clipboard_type))
128    return WebString();
129
130  base::string16 data;
131  client_->ReadCustomData(clipboard_type, type, &data);
132  return data;
133}
134
135void WebClipboardImpl::writePlainText(const WebString& plain_text) {
136  ScopedClipboardWriterGlue scw(client_);
137  scw.WriteText(plain_text);
138}
139
140void WebClipboardImpl::writeHTML(
141    const WebString& html_text, const WebURL& source_url,
142    const WebString& plain_text, bool write_smart_paste) {
143  ScopedClipboardWriterGlue scw(client_);
144  scw.WriteHTML(html_text, source_url.spec());
145  scw.WriteText(plain_text);
146
147  if (write_smart_paste)
148    scw.WriteWebSmartPaste();
149}
150
151void WebClipboardImpl::writeImage(const WebImage& image,
152                                  const WebURL& url,
153                                  const WebString& title) {
154  ScopedClipboardWriterGlue scw(client_);
155
156  if (!image.isNull()) {
157    const SkBitmap& bitmap = image.getSkBitmap();
158    // WriteBitmapFromPixels expects 32-bit data.
159    DCHECK_EQ(bitmap.colorType(), kN32_SkColorType);
160
161    SkAutoLockPixels locked(bitmap);
162    void *pixels = bitmap.getPixels();
163    // TODO(piman): this should not be NULL, but it is. crbug.com/369621
164    if (!pixels)
165      return;
166    scw.WriteBitmapFromPixels(pixels, image.size());
167  }
168
169  if (!url.isEmpty()) {
170    scw.WriteBookmark(title, url.spec());
171#if !defined(OS_MACOSX)
172    // When writing the image, we also write the image markup so that pasting
173    // into rich text editors, such as Gmail, reveals the image. We also don't
174    // want to call writeText(), since some applications (WordPad) don't pick
175    // the image if there is also a text format on the clipboard.
176    // We also don't want to write HTML on a Mac, since Mail.app prefers to use
177    // the image markup over attaching the actual image. See
178    // http://crbug.com/33016 for details.
179    scw.WriteHTML(base::UTF8ToUTF16(URLToImageMarkup(url, title)),
180                  std::string());
181#endif
182  }
183}
184
185void WebClipboardImpl::writeDataObject(const WebDragData& data) {
186  ScopedClipboardWriterGlue scw(client_);
187
188  const DropData& data_object = DropDataBuilder::Build(data);
189  // TODO(dcheng): Properly support text/uri-list here.
190  if (!data_object.text.is_null())
191    scw.WriteText(data_object.text.string());
192  if (!data_object.html.is_null())
193    scw.WriteHTML(data_object.html.string(), std::string());
194  // If there is no custom data, avoid calling WritePickledData. This ensures
195  // that ScopedClipboardWriterGlue's dtor remains a no-op if the page didn't
196  // modify the DataTransfer object, which is important to avoid stomping on
197  // any clipboard contents written by extension functions such as
198  // chrome.bookmarkManagerPrivate.copy.
199  if (!data_object.custom_data.empty()) {
200    Pickle pickle;
201    ui::WriteCustomDataToPickle(data_object.custom_data, &pickle);
202    scw.WritePickledData(pickle, ui::Clipboard::GetWebCustomDataFormatType());
203  }
204}
205
206bool WebClipboardImpl::ConvertBufferType(Buffer buffer,
207                                         ui::ClipboardType* result) {
208  *result = ui::CLIPBOARD_TYPE_COPY_PASTE;
209  switch (buffer) {
210    case BufferStandard:
211      break;
212    case BufferSelection:
213#if defined(USE_X11) && !defined(OS_CHROMEOS)
214      *result = ui::CLIPBOARD_TYPE_SELECTION;
215      break;
216#else
217      // Chrome OS and non-X11 unix builds do not support
218      // the X selection clipboad.
219      // TODO: remove the need for this case, see http://crbug.com/361753
220      return false;
221#endif
222    default:
223      NOTREACHED();
224      return false;
225  }
226  return true;
227}
228
229}  // namespace content
230