blob: c08b03fcee0b7230918df0b81d47172e3cd50cde [file] [log] [blame]
/*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "config.h"
#include "ClipboardGtk.h"
#include "CachedImage.h"
#include "DragData.h"
#include "Editor.h"
#include "Element.h"
#include "FileList.h"
#include "Frame.h"
#include "Image.h"
#include "NotImplemented.h"
#include "Pasteboard.h"
#include "PasteboardHelper.h"
#include "RenderImage.h"
#include "ScriptExecutionContext.h"
#include "StringHash.h"
#include "markup.h"
#include <wtf/text/CString.h>
#include <gtk/gtk.h>
namespace WebCore {
enum ClipboardType {
ClipboardTypeText,
ClipboardTypeMarkup,
ClipboardTypeURIList,
ClipboardTypeURL,
ClipboardTypeImage,
ClipboardTypeUnknown
};
PassRefPtr<Clipboard> Editor::newGeneralClipboard(ClipboardAccessPolicy policy, Frame* frame)
{
return ClipboardGtk::create(policy, gtk_clipboard_get_for_display(gdk_display_get_default(), GDK_SELECTION_CLIPBOARD), false, frame);
}
PassRefPtr<Clipboard> Clipboard::create(ClipboardAccessPolicy policy, DragData* dragData, Frame* frame)
{
return ClipboardGtk::create(policy, dragData->platformData(), true, frame);
}
ClipboardGtk::ClipboardGtk(ClipboardAccessPolicy policy, GtkClipboard* clipboard, Frame* frame)
: Clipboard(policy, false)
, m_dataObject(DataObjectGtk::forClipboard(clipboard))
, m_clipboard(clipboard)
, m_helper(Pasteboard::generalPasteboard()->helper())
, m_frame(frame)
{
}
ClipboardGtk::ClipboardGtk(ClipboardAccessPolicy policy, PassRefPtr<DataObjectGtk> dataObject, bool forDragging, Frame* frame)
: Clipboard(policy, forDragging)
, m_dataObject(dataObject)
, m_clipboard(0)
, m_helper(Pasteboard::generalPasteboard()->helper())
, m_frame(frame)
{
}
ClipboardGtk::~ClipboardGtk()
{
}
static ClipboardType dataObjectTypeFromHTMLClipboardType(const String& rawType)
{
String type(rawType.stripWhiteSpace());
// Two special cases for IE compatibility
if (type == "Text")
return ClipboardTypeText;
if (type == "URL")
return ClipboardTypeURL;
// From the Mac port: Ignore any trailing charset - JS strings are
// Unicode, which encapsulates the charset issue.
if (type == "text/plain" || type.startsWith("text/plain;"))
return ClipboardTypeText;
if (type == "text/html" || type.startsWith("text/html;"))
return ClipboardTypeMarkup;
if (type == "Files" || type == "text/uri-list" || type.startsWith("text/uri-list;"))
return ClipboardTypeURIList;
// Not a known type, so just default to using the text portion.
return ClipboardTypeUnknown;
}
void ClipboardGtk::clearData(const String& typeString)
{
if (policy() != ClipboardWritable)
return;
ClipboardType type = dataObjectTypeFromHTMLClipboardType(typeString);
switch (type) {
case ClipboardTypeURIList:
case ClipboardTypeURL:
m_dataObject->clearURIList();
break;
case ClipboardTypeMarkup:
m_dataObject->clearMarkup();
break;
case ClipboardTypeText:
m_dataObject->clearText();
break;
case ClipboardTypeUnknown:
default:
m_dataObject->clear();
}
if (m_clipboard)
m_helper->writeClipboardContents(m_clipboard);
}
void ClipboardGtk::clearAllData()
{
if (policy() != ClipboardWritable)
return;
m_dataObject->clear();
if (m_clipboard)
m_helper->writeClipboardContents(m_clipboard);
}
static String joinURIList(Vector<KURL> uriList)
{
if (uriList.isEmpty())
return String();
String joined(uriList[0].string());
for (size_t i = 1; i < uriList.size(); i++) {
joined.append("\r\n");
joined.append(uriList[i].string());
}
return joined;
}
String ClipboardGtk::getData(const String& typeString, bool& success) const
{
success = false; // Pessimism.
if (policy() != ClipboardReadable || !m_dataObject)
return String();
if (m_clipboard)
m_helper->getClipboardContents(m_clipboard);
ClipboardType type = dataObjectTypeFromHTMLClipboardType(typeString);
if (type == ClipboardTypeURIList) {
if (!m_dataObject->hasURIList())
return String();
success = true;
return joinURIList(m_dataObject->uriList());
}
if (type == ClipboardTypeURL) {
if (!m_dataObject->hasURL())
return String();
success = true;
return m_dataObject->url();
}
if (type == ClipboardTypeMarkup) {
if (!m_dataObject->hasMarkup())
return String();
success = true;
return m_dataObject->markup();
}
if (type == ClipboardTypeText) {
if (!m_dataObject->hasText())
return String();
success = true;
return m_dataObject->text();
}
return String();
}
bool ClipboardGtk::setData(const String& typeString, const String& data)
{
if (policy() != ClipboardWritable)
return false;
bool success = false;
ClipboardType type = dataObjectTypeFromHTMLClipboardType(typeString);
if (type == ClipboardTypeURIList || type == ClipboardTypeURL) {
Vector<KURL> uriList;
gchar** uris = g_uri_list_extract_uris(data.utf8().data());
if (uris) {
gchar** currentURI = uris;
while (*currentURI) {
uriList.append(KURL(KURL(), *currentURI));
currentURI++;
}
g_strfreev(uris);
m_dataObject->setURIList(uriList);
success = true;
}
} else if (type == ClipboardTypeMarkup) {
m_dataObject->setMarkup(data);
success = true;
} else if (type == ClipboardTypeText) {
m_dataObject->setText(data);
success = true;
}
if (success && m_clipboard)
m_helper->writeClipboardContents(m_clipboard);
return success;
}
HashSet<String> ClipboardGtk::types() const
{
if (policy() != ClipboardReadable && policy() != ClipboardTypesReadable)
return HashSet<String>();
if (m_clipboard)
m_helper->getClipboardContents(m_clipboard);
HashSet<String> types;
if (m_dataObject->hasText()) {
types.add("text/plain");
types.add("Text");
}
if (m_dataObject->hasMarkup())
types.add("text/html");
if (m_dataObject->hasURIList()) {
types.add("text/uri-list");
types.add("URL");
types.add("Files");
}
return types;
}
PassRefPtr<FileList> ClipboardGtk::files() const
{
if (policy() != ClipboardReadable)
return FileList::create();
if (m_clipboard)
m_helper->getClipboardContents(m_clipboard);
RefPtr<FileList> fileList = FileList::create();
Vector<String> fileVector(m_dataObject->files());
ScriptExecutionContext* scriptExecutionContext = m_frame->document()->scriptExecutionContext();
for (size_t i = 0; i < fileVector.size(); i++)
fileList->append(File::create(scriptExecutionContext, fileVector[i]));
return fileList.release();
}
IntPoint ClipboardGtk::dragLocation() const
{
notImplemented();
return IntPoint(0, 0);
}
CachedImage* ClipboardGtk::dragImage() const
{
notImplemented();
return 0;
}
void ClipboardGtk::setDragImage(CachedImage*, const IntPoint&)
{
notImplemented();
}
Node* ClipboardGtk::dragImageElement()
{
notImplemented();
return 0;
}
void ClipboardGtk::setDragImageElement(Node*, const IntPoint&)
{
notImplemented();
}
DragImageRef ClipboardGtk::createDragImage(IntPoint&) const
{
notImplemented();
return 0;
}
static CachedImage* getCachedImage(Element* element)
{
// Attempt to pull CachedImage from element
ASSERT(element);
RenderObject* renderer = element->renderer();
if (!renderer || !renderer->isImage())
return 0;
RenderImage* image = static_cast<RenderImage*>(renderer);
if (image->cachedImage() && !image->cachedImage()->errorOccurred())
return image->cachedImage();
return 0;
}
void ClipboardGtk::declareAndWriteDragImage(Element* element, const KURL& url, const String& label, Frame*)
{
CachedImage* cachedImage = getCachedImage(element);
if (!cachedImage || !cachedImage->isLoaded())
return;
GdkPixbuf* pixbuf = cachedImage->image()->getGdkPixbuf();
if (!pixbuf)
return;
GtkClipboard* imageClipboard = gtk_clipboard_get(gdk_atom_intern_static_string("WebKitClipboardImage"));
gtk_clipboard_clear(imageClipboard);
gtk_clipboard_set_image(imageClipboard, pixbuf);
g_object_unref(pixbuf);
writeURL(url, label, 0);
}
void ClipboardGtk::writeURL(const KURL& url, const String& label, Frame*)
{
m_dataObject->setURL(url, label);
if (m_clipboard)
m_helper->writeClipboardContents(m_clipboard);
}
void ClipboardGtk::writeRange(Range* range, Frame* frame)
{
ASSERT(range);
m_dataObject->setText(frame->selectedText());
m_dataObject->setMarkup(createMarkup(range, 0, AnnotateForInterchange, false, AbsoluteURLs));
if (m_clipboard)
m_helper->writeClipboardContents(m_clipboard);
}
void ClipboardGtk::writePlainText(const String& text)
{
m_dataObject->setText(text);
if (m_clipboard)
m_helper->writeClipboardContents(m_clipboard);
}
bool ClipboardGtk::hasData()
{
if (m_clipboard)
m_helper->getClipboardContents(m_clipboard);
return m_dataObject->hasText() || m_dataObject->hasMarkup()
|| m_dataObject->hasURIList() || m_dataObject->hasImage();
}
}