Home | History | Annotate | Download | only in gtk
      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