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 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 54 PassRefPtr<Clipboard> Clipboard::create(ClipboardAccessPolicy policy, DragData* dragData, Frame* frame) 55 { 56 return ClipboardGtk::create(policy, dragData->platformData(), DragAndDrop, frame); 57 } 58 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 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 77 ClipboardGtk::~ClipboardGtk() 78 { 79 } 80 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 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 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 142 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 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 192 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 221 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 236 void ClipboardGtk::setDragImage(CachedImage* image, const IntPoint& location) 237 { 238 setDragImage(image, 0, location); 239 } 240 241 void ClipboardGtk::setDragImageElement(Node* element, const IntPoint& location) 242 { 243 setDragImage(0, element, location); 244 } 245 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 261 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 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 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 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 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 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 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