1 /*
2 * This library is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU Lesser General Public
4 * License as published by the Free Software Foundation; either
5 * version 2 of the License, or (at your option) any later version.
6 *
7 * This library is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 * Lesser General Public License for more details.
11 *
12 * You should have received a copy of the GNU Lesser General Public
13 * License along with this library; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
15 */
16
17 #include "config.h"
18 #include "ClipboardGtk.h"
19
20 #include "CachedImage.h"
21 #include "DragData.h"
22 #include "Editor.h"
23 #include "Element.h"
24 #include "FileList.h"
25 #include "Frame.h"
26 #include "HTMLNames.h"
27 #include "Image.h"
28 #include "NotImplemented.h"
29 #include "Pasteboard.h"
30 #include "PasteboardHelper.h"
31 #include "RenderImage.h"
32 #include "ScriptExecutionContext.h"
33 #include "markup.h"
34 #include <wtf/text/CString.h>
35 #include <wtf/text/StringHash.h>
36 #include <gtk/gtk.h>
37
38 namespace WebCore {
39
40 enum ClipboardDataType {
41 ClipboardDataTypeText,
42 ClipboardDataTypeMarkup,
43 ClipboardDataTypeURIList,
44 ClipboardDataTypeURL,
45 ClipboardDataTypeImage,
46 ClipboardDataTypeUnknown
47 };
48
newGeneralClipboard(ClipboardAccessPolicy policy,Frame * frame)49 PassRefPtr<Clipboard> Editor::newGeneralClipboard(ClipboardAccessPolicy policy, Frame* frame)
50 {
51 return ClipboardGtk::create(policy, gtk_clipboard_get_for_display(gdk_display_get_default(), GDK_SELECTION_CLIPBOARD), frame);
52 }
53
create(ClipboardAccessPolicy policy,DragData * dragData,Frame * frame)54 PassRefPtr<Clipboard> Clipboard::create(ClipboardAccessPolicy policy, DragData* dragData, Frame* frame)
55 {
56 return ClipboardGtk::create(policy, dragData->platformData(), DragAndDrop, frame);
57 }
58
ClipboardGtk(ClipboardAccessPolicy policy,GtkClipboard * clipboard,Frame * frame)59 ClipboardGtk::ClipboardGtk(ClipboardAccessPolicy policy, GtkClipboard* clipboard, Frame* frame)
60 : Clipboard(policy, CopyAndPaste)
61 , m_dataObject(DataObjectGtk::forClipboard(clipboard))
62 , m_clipboard(clipboard)
63 , m_helper(Pasteboard::generalPasteboard()->helper())
64 , m_frame(frame)
65 {
66 }
67
ClipboardGtk(ClipboardAccessPolicy policy,PassRefPtr<DataObjectGtk> dataObject,ClipboardType clipboardType,Frame * frame)68 ClipboardGtk::ClipboardGtk(ClipboardAccessPolicy policy, PassRefPtr<DataObjectGtk> dataObject, ClipboardType clipboardType, Frame* frame)
69 : Clipboard(policy, clipboardType)
70 , m_dataObject(dataObject)
71 , m_clipboard(0)
72 , m_helper(Pasteboard::generalPasteboard()->helper())
73 , m_frame(frame)
74 {
75 }
76
~ClipboardGtk()77 ClipboardGtk::~ClipboardGtk()
78 {
79 }
80
dataObjectTypeFromHTMLClipboardType(const String & rawType)81 static ClipboardDataType dataObjectTypeFromHTMLClipboardType(const String& rawType)
82 {
83 String type(rawType.stripWhiteSpace());
84
85 // Two special cases for IE compatibility
86 if (type == "Text" || type == "text")
87 return ClipboardDataTypeText;
88 if (type == "URL")
89 return ClipboardDataTypeURL;
90
91 // From the Mac port: Ignore any trailing charset - JS strings are
92 // Unicode, which encapsulates the charset issue.
93 if (type == "text/plain" || type.startsWith("text/plain;"))
94 return ClipboardDataTypeText;
95 if (type == "text/html" || type.startsWith("text/html;"))
96 return ClipboardDataTypeMarkup;
97 if (type == "Files" || type == "text/uri-list" || type.startsWith("text/uri-list;"))
98 return ClipboardDataTypeURIList;
99
100 // Not a known type, so just default to using the text portion.
101 return ClipboardDataTypeUnknown;
102 }
103
clearData(const String & typeString)104 void ClipboardGtk::clearData(const String& typeString)
105 {
106 if (policy() != ClipboardWritable)
107 return;
108
109 ClipboardDataType type = dataObjectTypeFromHTMLClipboardType(typeString);
110 switch (type) {
111 case ClipboardDataTypeURIList:
112 case ClipboardDataTypeURL:
113 m_dataObject->clearURIList();
114 break;
115 case ClipboardDataTypeMarkup:
116 m_dataObject->clearMarkup();
117 break;
118 case ClipboardDataTypeText:
119 m_dataObject->clearText();
120 break;
121 case ClipboardDataTypeUnknown:
122 default:
123 m_dataObject->clear();
124 }
125
126 if (m_clipboard)
127 m_helper->writeClipboardContents(m_clipboard);
128 }
129
130
clearAllData()131 void ClipboardGtk::clearAllData()
132 {
133 if (policy() != ClipboardWritable)
134 return;
135
136 m_dataObject->clear();
137
138 if (m_clipboard)
139 m_helper->writeClipboardContents(m_clipboard);
140 }
141
getData(const String & typeString,bool & success) const142 String ClipboardGtk::getData(const String& typeString, bool& success) const
143 {
144 success = true; // According to http://www.whatwg.org/specs/web-apps/current-work/multipage/dnd.html
145 // "The getData(format) method must return the data that is associated with the type format converted
146 // to ASCII lowercase, if any, and must return the empty string otherwise." Since success == false
147 // results in an 'undefined' return value, we always want to return success == true. This parameter
148 // should eventually be removed.
149 if (policy() != ClipboardReadable || !m_dataObject)
150 return String();
151
152 if (m_clipboard)
153 m_helper->getClipboardContents(m_clipboard);
154
155 ClipboardDataType type = dataObjectTypeFromHTMLClipboardType(typeString);
156 if (type == ClipboardDataTypeURIList)
157 return m_dataObject->uriList();
158 if (type == ClipboardDataTypeURL)
159 return m_dataObject->url();
160 if (type == ClipboardDataTypeMarkup)
161 return m_dataObject->markup();
162 if (type == ClipboardDataTypeText)
163 return m_dataObject->text();
164
165 return String();
166 }
167
setData(const String & typeString,const String & data)168 bool ClipboardGtk::setData(const String& typeString, const String& data)
169 {
170 if (policy() != ClipboardWritable)
171 return false;
172
173 bool success = false;
174 ClipboardDataType type = dataObjectTypeFromHTMLClipboardType(typeString);
175 if (type == ClipboardDataTypeURIList || type == ClipboardDataTypeURL) {
176 m_dataObject->setURIList(data);
177 success = true;
178 } else if (type == ClipboardDataTypeMarkup) {
179 m_dataObject->setMarkup(data);
180 success = true;
181 } else if (type == ClipboardDataTypeText) {
182 m_dataObject->setText(data);
183 success = true;
184 }
185
186 if (success && m_clipboard)
187 m_helper->writeClipboardContents(m_clipboard);
188
189 return success;
190 }
191
types() const192 HashSet<String> ClipboardGtk::types() const
193 {
194 if (policy() != ClipboardReadable && policy() != ClipboardTypesReadable)
195 return HashSet<String>();
196
197 if (m_clipboard)
198 m_helper->getClipboardContents(m_clipboard);
199
200 HashSet<String> types;
201 if (m_dataObject->hasText()) {
202 types.add("text/plain");
203 types.add("Text");
204 types.add("text");
205 }
206
207 if (m_dataObject->hasMarkup())
208 types.add("text/html");
209
210 if (m_dataObject->hasURIList()) {
211 types.add("text/uri-list");
212 types.add("URL");
213 }
214
215 if (m_dataObject->hasFilenames())
216 types.add("Files");
217
218 return types;
219 }
220
files() const221 PassRefPtr<FileList> ClipboardGtk::files() const
222 {
223 if (policy() != ClipboardReadable)
224 return FileList::create();
225
226 if (m_clipboard)
227 m_helper->getClipboardContents(m_clipboard);
228
229 RefPtr<FileList> fileList = FileList::create();
230 const Vector<String>& filenames = m_dataObject->filenames();
231 for (size_t i = 0; i < filenames.size(); i++)
232 fileList->append(File::create(filenames[i]));
233 return fileList.release();
234 }
235
setDragImage(CachedImage * image,const IntPoint & location)236 void ClipboardGtk::setDragImage(CachedImage* image, const IntPoint& location)
237 {
238 setDragImage(image, 0, location);
239 }
240
setDragImageElement(Node * element,const IntPoint & location)241 void ClipboardGtk::setDragImageElement(Node* element, const IntPoint& location)
242 {
243 setDragImage(0, element, location);
244 }
245
setDragImage(CachedImage * image,Node * element,const IntPoint & location)246 void ClipboardGtk::setDragImage(CachedImage* image, Node* element, const IntPoint& location)
247 {
248 if (policy() != ClipboardImageWritable && policy() != ClipboardWritable)
249 return;
250
251 if (m_dragImage)
252 m_dragImage->removeClient(this);
253 m_dragImage = image;
254 if (m_dragImage)
255 m_dragImage->addClient(this);
256
257 m_dragLoc = location;
258 m_dragImageElement = element;
259 }
260
createDragImage(IntPoint & location) const261 DragImageRef ClipboardGtk::createDragImage(IntPoint& location) const
262 {
263 location = m_dragLoc;
264 if (!m_dragImage)
265 return 0;
266
267 return createDragImageFromImage(m_dragImage->image());
268 }
269
getCachedImage(Element * element)270 static CachedImage* getCachedImage(Element* element)
271 {
272 // Attempt to pull CachedImage from element
273 ASSERT(element);
274 RenderObject* renderer = element->renderer();
275 if (!renderer || !renderer->isImage())
276 return 0;
277
278 RenderImage* image = static_cast<RenderImage*>(renderer);
279 if (image->cachedImage() && !image->cachedImage()->errorOccurred())
280 return image->cachedImage();
281
282 return 0;
283 }
284
declareAndWriteDragImage(Element * element,const KURL & url,const String & label,Frame * frame)285 void ClipboardGtk::declareAndWriteDragImage(Element* element, const KURL& url, const String& label, Frame* frame)
286 {
287 m_dataObject->setURL(url, label);
288 m_dataObject->setMarkup(createMarkup(element, IncludeNode, 0, AbsoluteURLs));
289
290 CachedImage* image = getCachedImage(element);
291 if (!image || !image->isLoaded())
292 return;
293
294 GRefPtr<GdkPixbuf> pixbuf = adoptGRef(image->image()->getGdkPixbuf());
295 if (!pixbuf)
296 return;
297
298 m_dataObject->setImage(pixbuf.get());
299 }
300
writeURL(const KURL & url,const String & label,Frame *)301 void ClipboardGtk::writeURL(const KURL& url, const String& label, Frame*)
302 {
303 m_dataObject->setURL(url, label);
304 if (m_clipboard)
305 m_helper->writeClipboardContents(m_clipboard);
306 }
307
writeRange(Range * range,Frame * frame)308 void ClipboardGtk::writeRange(Range* range, Frame* frame)
309 {
310 ASSERT(range);
311
312 m_dataObject->setText(frame->editor()->selectedText());
313 m_dataObject->setMarkup(createMarkup(range, 0, AnnotateForInterchange, false, AbsoluteURLs));
314
315 if (m_clipboard)
316 m_helper->writeClipboardContents(m_clipboard);
317 }
318
writePlainText(const String & text)319 void ClipboardGtk::writePlainText(const String& text)
320 {
321 m_dataObject->setText(text);
322
323 if (m_clipboard)
324 m_helper->writeClipboardContents(m_clipboard);
325 }
326
hasData()327 bool ClipboardGtk::hasData()
328 {
329 if (m_clipboard)
330 m_helper->getClipboardContents(m_clipboard);
331
332 return m_dataObject->hasText() || m_dataObject->hasMarkup()
333 || m_dataObject->hasURIList() || m_dataObject->hasImage();
334 }
335
336 }
337