1/*
2 * Copyright (C) 2007 Holger Hans Peter Freyther
3 * Copyright (C) 2007 Alp Toker <alp@atoker.com>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20#include "config.h"
21#include "Pasteboard.h"
22
23#include "Color.h"
24#include "DragData.h"
25#include "Image.h"
26#include "NotImplemented.h"
27#include "PasteboardStrategy.h"
28#include "PlatformStrategies.h"
29#include "SelectionData.h"
30#include <wtf/NeverDestroyed.h>
31#include <wtf/URL.h>
32
33namespace WebCore {
34
35enum ClipboardDataType {
36 ClipboardDataTypeText,
37 ClipboardDataTypeMarkup,
38 ClipboardDataTypeURIList,
39 ClipboardDataTypeURL,
40 ClipboardDataTypeImage,
41 ClipboardDataTypeUnknown
42};
43
44std::unique_ptr<Pasteboard> Pasteboard::createForCopyAndPaste()
45{
46 return std::make_unique<Pasteboard>("CLIPBOARD");
47}
48
49std::unique_ptr<Pasteboard> Pasteboard::createForGlobalSelection()
50{
51 return std::make_unique<Pasteboard>("PRIMARY");
52}
53
54#if ENABLE(DRAG_SUPPORT)
55std::unique_ptr<Pasteboard> Pasteboard::createForDragAndDrop()
56{
57 return std::make_unique<Pasteboard>(SelectionData::create());
58}
59
60std::unique_ptr<Pasteboard> Pasteboard::createForDragAndDrop(const DragData& dragData)
61{
62 ASSERT(dragData.platformData());
63 return std::make_unique<Pasteboard>(*dragData.platformData());
64}
65#endif
66
67Pasteboard::Pasteboard(SelectionData& selectionData)
68 : m_selectionData(selectionData)
69{
70}
71
72Pasteboard::Pasteboard(const String& name)
73 : m_selectionData(SelectionData::create())
74 , m_name(name)
75{
76}
77
78Pasteboard::Pasteboard()
79 : m_selectionData(SelectionData::create())
80{
81}
82
83Pasteboard::~Pasteboard() = default;
84
85const SelectionData& Pasteboard::selectionData() const
86{
87 return m_selectionData.get();
88}
89
90static ClipboardDataType selectionDataTypeFromHTMLClipboardType(const String& type)
91{
92 // From the Mac port: Ignore any trailing charset - JS strings are
93 // Unicode, which encapsulates the charset issue.
94 if (type == "text/plain")
95 return ClipboardDataTypeText;
96 if (type == "text/html")
97 return ClipboardDataTypeMarkup;
98 if (type == "Files" || type == "text/uri-list")
99 return ClipboardDataTypeURIList;
100
101 // Not a known type, so just default to using the text portion.
102 return ClipboardDataTypeUnknown;
103}
104
105void Pasteboard::writeToClipboard()
106{
107 if (m_name.isNull())
108 return;
109
110 platformStrategies()->pasteboardStrategy()->writeToClipboard(m_name, m_selectionData);
111}
112
113void Pasteboard::readFromClipboard()
114{
115 if (m_name.isNull())
116 return;
117 m_selectionData = platformStrategies()->pasteboardStrategy()->readFromClipboard(m_name);
118}
119
120void Pasteboard::writeString(const String& type, const String& data)
121{
122 switch (selectionDataTypeFromHTMLClipboardType(type)) {
123 case ClipboardDataTypeURIList:
124 case ClipboardDataTypeURL:
125 m_selectionData->setURIList(data);
126 break;
127 case ClipboardDataTypeMarkup:
128 m_selectionData->setMarkup(data);
129 break;
130 case ClipboardDataTypeText:
131 m_selectionData->setText(data);
132 break;
133 case ClipboardDataTypeUnknown:
134 m_selectionData->setUnknownTypeData(type, data);
135 break;
136 case ClipboardDataTypeImage:
137 break;
138 }
139 writeToClipboard();
140}
141
142void Pasteboard::writePlainText(const String& text, SmartReplaceOption smartReplaceOption)
143{
144 m_selectionData->clearAll();
145 m_selectionData->setText(text);
146 m_selectionData->setCanSmartReplace(smartReplaceOption == CanSmartReplace);
147
148 writeToClipboard();
149}
150
151void Pasteboard::write(const PasteboardURL& pasteboardURL)
152{
153 ASSERT(!pasteboardURL.url.isEmpty());
154
155 m_selectionData->clearAll();
156 m_selectionData->setURL(pasteboardURL.url, pasteboardURL.title);
157
158 writeToClipboard();
159}
160
161void Pasteboard::writeTrustworthyWebURLsPboardType(const PasteboardURL&)
162{
163 notImplemented();
164}
165
166void Pasteboard::write(const PasteboardImage& pasteboardImage)
167{
168 m_selectionData->clearAll();
169 if (!pasteboardImage.url.url.isEmpty()) {
170 m_selectionData->setURL(pasteboardImage.url.url, pasteboardImage.url.title);
171 m_selectionData->setMarkup(pasteboardImage.url.markup);
172 }
173 m_selectionData->setImage(pasteboardImage.image.get());
174
175 writeToClipboard();
176}
177
178void Pasteboard::write(const PasteboardWebContent& pasteboardContent)
179{
180 m_selectionData->clearAll();
181 m_selectionData->setText(pasteboardContent.text);
182 m_selectionData->setMarkup(pasteboardContent.markup);
183 m_selectionData->setCanSmartReplace(pasteboardContent.canSmartCopyOrDelete);
184
185 writeToClipboard();
186}
187
188void Pasteboard::clear()
189{
190 // We do not clear filenames. According to the spec: "The clearData() method
191 // does not affect whether any files were included in the drag, so the types
192 // attribute's list might still not be empty after calling clearData() (it would
193 // still contain the "Files" string if any files were included in the drag)."
194 m_selectionData->clearAllExceptFilenames();
195 writeToClipboard();
196}
197
198void Pasteboard::clear(const String& type)
199{
200 switch (selectionDataTypeFromHTMLClipboardType(type)) {
201 case ClipboardDataTypeURIList:
202 case ClipboardDataTypeURL:
203 m_selectionData->clearURIList();
204 break;
205 case ClipboardDataTypeMarkup:
206 m_selectionData->clearMarkup();
207 break;
208 case ClipboardDataTypeText:
209 m_selectionData->clearText();
210 break;
211 case ClipboardDataTypeImage:
212 m_selectionData->clearImage();
213 break;
214 case ClipboardDataTypeUnknown:
215 m_selectionData->clearAll();
216 break;
217 }
218
219 writeToClipboard();
220}
221
222bool Pasteboard::canSmartReplace()
223{
224 readFromClipboard();
225 return m_selectionData->canSmartReplace();
226}
227
228#if ENABLE(DRAG_SUPPORT)
229void Pasteboard::setDragImage(DragImage, const IntPoint&)
230{
231}
232#endif
233
234void Pasteboard::read(PasteboardPlainText& text)
235{
236 readFromClipboard();
237 text.text = m_selectionData->text();
238}
239
240void Pasteboard::read(PasteboardWebContentReader&, WebContentReadingPolicy)
241{
242}
243
244void Pasteboard::read(PasteboardFileReader& reader)
245{
246 readFromClipboard();
247 for (auto& filename : m_selectionData->filenames())
248 reader.readFilename(filename);
249}
250
251bool Pasteboard::hasData()
252{
253 readFromClipboard();
254 return m_selectionData->hasText() || m_selectionData->hasMarkup() || m_selectionData->hasURIList() || m_selectionData->hasImage() || m_selectionData->hasUnknownTypeData();
255}
256
257Vector<String> Pasteboard::typesSafeForBindings(const String&)
258{
259 notImplemented(); // webkit.org/b/177633: [GTK] Move to new Pasteboard API
260 return { };
261}
262
263Vector<String> Pasteboard::typesForLegacyUnsafeBindings()
264{
265 readFromClipboard();
266
267 Vector<String> types;
268 if (m_selectionData->hasText()) {
269 types.append("text/plain"_s);
270 types.append("Text"_s);
271 types.append("text"_s);
272 }
273
274 if (m_selectionData->hasMarkup())
275 types.append("text/html"_s);
276
277 if (m_selectionData->hasURIList()) {
278 types.append("text/uri-list"_s);
279 types.append("URL"_s);
280 }
281
282 for (auto& key : m_selectionData->unknownTypes().keys())
283 types.append(key);
284
285 return types;
286}
287
288String Pasteboard::readOrigin()
289{
290 notImplemented(); // webkit.org/b/177633: [GTK] Move to new Pasteboard API
291 return { };
292}
293
294String Pasteboard::readString(const String& type)
295{
296 readFromClipboard();
297
298 switch (selectionDataTypeFromHTMLClipboardType(type)) {
299 case ClipboardDataTypeURIList:
300 return m_selectionData->uriList();
301 case ClipboardDataTypeURL:
302 return m_selectionData->url();
303 case ClipboardDataTypeMarkup:
304 return m_selectionData->markup();
305 case ClipboardDataTypeText:
306 return m_selectionData->text();
307 case ClipboardDataTypeUnknown:
308 return m_selectionData->unknownTypeData(type);
309 case ClipboardDataTypeImage:
310 break;
311 }
312
313 return String();
314}
315
316String Pasteboard::readStringInCustomData(const String&)
317{
318 notImplemented(); // webkit.org/b/177633: [GTK] Move to new Pasteboard API
319 return { };
320}
321
322Pasteboard::FileContentState Pasteboard::fileContentState()
323{
324 readFromClipboard();
325 return m_selectionData->filenames().isEmpty() ? FileContentState::NoFileOrImageData : FileContentState::MayContainFilePaths;
326}
327
328void Pasteboard::writeMarkup(const String&)
329{
330}
331
332void Pasteboard::writeCustomData(const PasteboardCustomData&)
333{
334}
335
336void Pasteboard::write(const Color&)
337{
338}
339
340}
341