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 "third_party/blink/renderer/core/clipboard/system_clipboard.h"
6
7 #include "base/memory/scoped_refptr.h"
8 #include "build/build_config.h"
9 #include "mojo/public/cpp/system/platform_handle.h"
10 #include "third_party/blink/public/common/browser_interface_broker_proxy.h"
11 #include "third_party/blink/public/common/thread_safe_browser_interface_broker_proxy.h"
12 #include "third_party/blink/public/platform/platform.h"
13 #include "third_party/blink/public/platform/web_drag_data.h"
14 #include "third_party/blink/public/platform/web_string.h"
15 #include "third_party/blink/renderer/core/clipboard/clipboard_mime_types.h"
16 #include "third_party/blink/renderer/core/clipboard/clipboard_utilities.h"
17 #include "third_party/blink/renderer/core/clipboard/data_object.h"
18 #include "third_party/blink/renderer/core/frame/local_frame.h"
19 #include "third_party/blink/renderer/platform/graphics/image.h"
20 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
21 #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
22 #include "third_party/skia/include/core/SkBitmap.h"
23
24 namespace blink {
25
26 namespace {
27
NonNullString(const String & string)28 String NonNullString(const String& string) {
29 return string.IsNull() ? g_empty_string16_bit : string;
30 }
31
32 } // namespace
33
SystemClipboard(LocalFrame * frame)34 SystemClipboard::SystemClipboard(LocalFrame* frame) {
35 frame->GetBrowserInterfaceBroker().GetInterface(
36 clipboard_.BindNewPipeAndPassReceiver());
37 }
38
IsSelectionMode() const39 bool SystemClipboard::IsSelectionMode() const {
40 return buffer_ == mojom::ClipboardBuffer::kSelection;
41 }
42
SetSelectionMode(bool selection_mode)43 void SystemClipboard::SetSelectionMode(bool selection_mode) {
44 buffer_ = selection_mode ? mojom::ClipboardBuffer::kSelection
45 : mojom::ClipboardBuffer::kStandard;
46 }
47
CanSmartReplace()48 bool SystemClipboard::CanSmartReplace() {
49 if (!IsValidBufferType(buffer_))
50 return false;
51 bool result = false;
52 clipboard_->IsFormatAvailable(mojom::ClipboardFormat::kSmartPaste, buffer_,
53 &result);
54 return result;
55 }
56
IsHTMLAvailable()57 bool SystemClipboard::IsHTMLAvailable() {
58 if (!IsValidBufferType(buffer_))
59 return false;
60 bool result = false;
61 clipboard_->IsFormatAvailable(mojom::ClipboardFormat::kHtml, buffer_,
62 &result);
63 return result;
64 }
65
SequenceNumber()66 uint64_t SystemClipboard::SequenceNumber() {
67 if (!IsValidBufferType(buffer_))
68 return 0;
69 uint64_t result = 0;
70 clipboard_->GetSequenceNumber(buffer_, &result);
71 return result;
72 }
73
ReadAvailableTypes()74 Vector<String> SystemClipboard::ReadAvailableTypes() {
75 if (!IsValidBufferType(buffer_))
76 return {};
77 Vector<String> types;
78 bool contains_filenames; // Unused argument.
79 clipboard_->ReadAvailableTypes(buffer_, &types, &contains_filenames);
80 return types;
81 }
82
ReadPlainText()83 String SystemClipboard::ReadPlainText() {
84 return ReadPlainText(buffer_);
85 }
86
ReadPlainText(mojom::ClipboardBuffer buffer)87 String SystemClipboard::ReadPlainText(mojom::ClipboardBuffer buffer) {
88 if (!IsValidBufferType(buffer))
89 return String();
90 String text;
91 clipboard_->ReadText(buffer, &text);
92 return text;
93 }
94
WritePlainText(const String & plain_text,SmartReplaceOption)95 void SystemClipboard::WritePlainText(const String& plain_text,
96 SmartReplaceOption) {
97 // TODO(https://crbug.com/106449): add support for smart replace, which is
98 // currently under-specified.
99 String text = plain_text;
100 #if defined(OS_WIN)
101 ReplaceNewlinesWithWindowsStyleNewlines(text);
102 #endif
103 clipboard_->WriteText(NonNullString(text));
104 }
105
ReadHTML(KURL & url,unsigned & fragment_start,unsigned & fragment_end)106 String SystemClipboard::ReadHTML(KURL& url,
107 unsigned& fragment_start,
108 unsigned& fragment_end) {
109 String html;
110 if (IsValidBufferType(buffer_)) {
111 clipboard_->ReadHtml(buffer_, &html, &url,
112 static_cast<uint32_t*>(&fragment_start),
113 static_cast<uint32_t*>(&fragment_end));
114 }
115 if (html.IsEmpty()) {
116 url = KURL();
117 fragment_start = 0;
118 fragment_end = 0;
119 }
120 return html;
121 }
122
WriteHTML(const String & markup,const KURL & document_url,const String & plain_text,SmartReplaceOption smart_replace_option)123 void SystemClipboard::WriteHTML(const String& markup,
124 const KURL& document_url,
125 const String& plain_text,
126 SmartReplaceOption smart_replace_option) {
127 String text = plain_text;
128 #if defined(OS_WIN)
129 ReplaceNewlinesWithWindowsStyleNewlines(text);
130 #endif
131 ReplaceNBSPWithSpace(text);
132
133 clipboard_->WriteHtml(NonNullString(markup), document_url);
134 clipboard_->WriteText(NonNullString(text));
135 if (smart_replace_option == kCanSmartReplace)
136 clipboard_->WriteSmartPasteMarker();
137 }
138
ReadRTF()139 String SystemClipboard::ReadRTF() {
140 if (!IsValidBufferType(buffer_))
141 return String();
142 String rtf;
143 clipboard_->ReadRtf(buffer_, &rtf);
144 return rtf;
145 }
146
ReadImage(mojom::ClipboardBuffer buffer)147 SkBitmap SystemClipboard::ReadImage(mojom::ClipboardBuffer buffer) {
148 if (!IsValidBufferType(buffer))
149 return SkBitmap();
150 SkBitmap image;
151 clipboard_->ReadImage(buffer, &image);
152 return image;
153 }
154
ReadImageAsImageMarkup(mojom::blink::ClipboardBuffer buffer)155 String SystemClipboard::ReadImageAsImageMarkup(
156 mojom::blink::ClipboardBuffer buffer) {
157 SkBitmap bitmap = ReadImage(buffer);
158 return BitmapToImageMarkup(bitmap);
159 }
160
WriteImageWithTag(Image * image,const KURL & url,const String & title)161 void SystemClipboard::WriteImageWithTag(Image* image,
162 const KURL& url,
163 const String& title) {
164 DCHECK(image);
165
166 PaintImage paint_image = image->PaintImageForCurrentFrame();
167 SkBitmap bitmap;
168 if (sk_sp<SkImage> sk_image = paint_image.GetSkImage())
169 sk_image->asLegacyBitmap(&bitmap);
170 clipboard_->WriteImage(bitmap);
171
172 if (url.IsValid() && !url.IsEmpty()) {
173 #if !defined(OS_MACOSX)
174 // See http://crbug.com/838808: Not writing text/plain on Mac for
175 // consistency between platforms, and to help fix errors in applications
176 // which prefer text/plain content over image content for compatibility with
177 // Microsoft Word.
178 clipboard_->WriteBookmark(url.GetString(), NonNullString(title));
179 #endif
180
181 // When writing the image, we also write the image markup so that pasting
182 // into rich text editors, such as Gmail, reveals the image. We also don't
183 // want to call writeText(), since some applications (WordPad) don't pick
184 // the image if there is also a text format on the clipboard.
185 clipboard_->WriteHtml(URLToImageMarkup(url, title), KURL());
186 }
187 }
188
WriteImage(const SkBitmap & bitmap)189 void SystemClipboard::WriteImage(const SkBitmap& bitmap) {
190 clipboard_->WriteImage(bitmap);
191 }
192
ReadCustomData(const String & type)193 String SystemClipboard::ReadCustomData(const String& type) {
194 if (!IsValidBufferType(buffer_))
195 return String();
196 String data;
197 clipboard_->ReadCustomData(buffer_, NonNullString(type), &data);
198 return data;
199 }
200
WriteDataObject(DataObject * data_object)201 void SystemClipboard::WriteDataObject(DataObject* data_object) {
202 DCHECK(data_object);
203 // This plagiarizes the logic in DropDataBuilder::Build, but only extracts the
204 // data needed for the implementation of WriteDataObject.
205 //
206 // We avoid calling the WriteFoo functions if there is no data associated with
207 // a type. This prevents stomping on clipboard contents that might have been
208 // written by extension functions such as chrome.bookmarkManagerPrivate.copy.
209 //
210 // TODO(slangley): Use a mojo struct to send web_drag_data and allow receiving
211 // side to extract the data required.
212 // TODO(dcheng): Properly support text/uri-list here.
213
214 HashMap<String, String> custom_data;
215 WebDragData data = data_object->ToWebDragData();
216 for (const WebDragData::Item& item : data.Items()) {
217 if (item.storage_type == WebDragData::Item::kStorageTypeString) {
218 if (item.string_type == kMimeTypeTextPlain) {
219 clipboard_->WriteText(NonNullString(item.string_data));
220 } else if (item.string_type == kMimeTypeTextHTML) {
221 clipboard_->WriteHtml(NonNullString(item.string_data), KURL());
222 } else if (item.string_type != kMimeTypeDownloadURL) {
223 custom_data.insert(item.string_type, NonNullString(item.string_data));
224 }
225 }
226 }
227 if (!custom_data.IsEmpty()) {
228 clipboard_->WriteCustomData(std::move(custom_data));
229 }
230 }
231
CommitWrite()232 void SystemClipboard::CommitWrite() {
233 clipboard_->CommitWrite();
234 }
235
IsValidBufferType(mojom::ClipboardBuffer buffer)236 bool SystemClipboard::IsValidBufferType(mojom::ClipboardBuffer buffer) {
237 switch (buffer) {
238 case mojom::ClipboardBuffer::kStandard:
239 return true;
240 case mojom::ClipboardBuffer::kSelection:
241 // mirroring ui/base/clipboard/clipboard.h
242 #if !defined(OS_WIN) && !defined(OS_MACOSX) && !defined(OS_CHROMEOS)
243 return true;
244 #else
245 // Chrome OS and non-X11 unix builds do not support
246 // the X selection clipboard.
247 // TODO(http://crbug.com/361753): remove the need for this case.
248 return false;
249 #endif
250 }
251 return true;
252 }
253
254 } // namespace blink
255