Commit 7b36a573 authored by mrobinson@webkit.org's avatar mrobinson@webkit.org
Browse files

2010-04-28 Martin Robinson <mrobinson@webkit.org>

        Reviewed by Gustavo Noronha.

        [GTK] Enable DOM clipboard and drag-and-drop access
        https://bugs.webkit.org/show_bug.cgi?id=30623

        Make ClipboardGtk a "live" DataTransfer object, able to modify
        the clipboard when setData(...) is called.

        * platform/gtk/Skipped: Uncomment tests that are now passing.
2010-04-28  Martin Robinson  <mrobinson@webkit.org>

        Reviewed by Gustavo Noronha.

        [GTK] Enable DOM clipboard and drag-and-drop access
        https://bugs.webkit.org/show_bug.cgi?id=30623

        Make ClipboardGtk a "live" DataTransfer object, able to modify
        the clipboard when setData(...) is called.

        * platform/gtk/ClipboardGtk.cpp:
        (WebCore::Editor::newGeneralClipboard): Pass the GtkClipboard into the factory method.
        (WebCore::ClipboardGtk::ClipboardGtk): Create two separate constructors, one for DnD data and one for clipboard data.
        (WebCore::dataObjectTypeFromHTMLClipboardType): Added.
        (WebCore::ClipboardGtk::clearData): Clear the member DataObject, optionally write the clipboard.
        (WebCore::ClipboardGtk::clearAllData): Ditto.
        (WebCore::joinURIList): Added.
        (WebCore::ClipboardGtk::getData): Get the data from the clipboard, if possible.
        (WebCore::ClipboardGtk::setData): Write data to the DataObject and maybe the clipboard.
        (WebCore::ClipboardGtk::types): Read the clipboard/DataObject to find applicable types.
        (WebCore::ClipboardGtk::files): Read the clipboard/DataObject to find the files.
        (WebCore::ClipboardGtk::writeURL): Write to the DataObject and maybe the clipboard.
        (WebCore::ClipboardGtk::writeRange): Ditto.
        (WebCore::ClipboardGtk::writePlainText): Ditto.
        (WebCore::ClipboardGtk::hasData): Query the clipboard/DataObject.
        * platform/gtk/ClipboardGtk.h:
        (WebCore::ClipboardGtk::create): Added one factory for pasteboard-backed DataObjects and one for DnD-backed objects.
        * platform/gtk/DataObjectGtk.cpp:
        (WebCore::replaceNonBreakingSpaceWithSpace): Added this helper function to clean &nbsp; from plain text.
        (WebCore::DataObjectGtk::markup): Actually return the range if it's set.
        (WebCore::DataObjectGtk::setText): Clean &nbsp; from plain text.
        (WebCore::DataObjectGtk::clearText): Added.
        (WebCore::DataObjectGtk::clearMarkup): Added.
        * platform/gtk/DataObjectGtk.h:
        (WebCore::DataObjectGtk::clearURIList): Added.
        (WebCore::DataObjectGtk::clearImage): Added.
        * platform/gtk/PasteboardHelper.cpp:
        (WebCore::PasteboardHelper::initializeTargetList): Added target ID's for URI list and Netscape URL targets.
        (WebCore::urisToKURLVector): Added.
        (WebCore::PasteboardHelper::getClipboardContents): Added.
        (WebCore::PasteboardHelper::fillSelectionData): Added logic for URI lists and Netscape URLs.
        (WebCore::PasteboardHelper::targetListForDataObject): Ditto.
        * platform/gtk/PasteboardHelper.h: Added default argument to writeClipboardContents and new method.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@58470 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 2bd947ea
2010-04-28 Martin Robinson <mrobinson@webkit.org>
Reviewed by Gustavo Noronha.
[GTK] Enable DOM clipboard and drag-and-drop access
https://bugs.webkit.org/show_bug.cgi?id=30623
Make ClipboardGtk a "live" DataTransfer object, able to modify
the clipboard when setData(...) is called.
* platform/gtk/Skipped: Uncomment tests that are now passing.
2010-04-28 Evan Martin <evan@chromium.org>
 
Reviewed by David Levin.
......
......@@ -740,7 +740,6 @@ editing/deleting/skip-virama-001.html
editing/deleting/smart-editing-disabled.html
editing/deleting/type-delete-after-quote-2.html
editing/execCommand/4128080-2.html
editing/execCommand/copy-without-selection.html
editing/execCommand/createLink.html
editing/execCommand/delete-image-in-anchor.html
editing/execCommand/enabling-and-selection-2.html
......@@ -773,17 +772,11 @@ editing/inserting/space-after-removeformat.html
editing/inserting/typing-tab-designmode.html
editing/pasteboard/4744008.html
editing/pasteboard/5368833.html
editing/pasteboard/5665299.html
editing/pasteboard/5780697-2.html
editing/pasteboard/copy-in-password-field.html
editing/pasteboard/copy-paste-float.html
editing/pasteboard/drag-image-in-about-blank-frame.html
editing/pasteboard/file-input-files-access.html
editing/pasteboard/get-data-text-plain-drop.html
editing/pasteboard/get-data-text-plain-paste.html
editing/pasteboard/onpaste-text-html.html
editing/pasteboard/paste-blockquote-before-blockquote.html
editing/pasteboard/paste-double-nested-blockquote-before-blockquote.html
editing/pasteboard/paste-into-anchor-text.html
editing/pasteboard/paste-plaintext-user-select-none.html
editing/pasteboard/paste-table-002.html
......
2010-04-28 Martin Robinson <mrobinson@webkit.org>
Reviewed by Gustavo Noronha.
[GTK] Enable DOM clipboard and drag-and-drop access
https://bugs.webkit.org/show_bug.cgi?id=30623
Make ClipboardGtk a "live" DataTransfer object, able to modify
the clipboard when setData(...) is called.
* platform/gtk/ClipboardGtk.cpp:
(WebCore::Editor::newGeneralClipboard): Pass the GtkClipboard into the factory method.
(WebCore::ClipboardGtk::ClipboardGtk): Create two separate constructors, one for DnD data and one for clipboard data.
(WebCore::dataObjectTypeFromHTMLClipboardType): Added.
(WebCore::ClipboardGtk::clearData): Clear the member DataObject, optionally write the clipboard.
(WebCore::ClipboardGtk::clearAllData): Ditto.
(WebCore::joinURIList): Added.
(WebCore::ClipboardGtk::getData): Get the data from the clipboard, if possible.
(WebCore::ClipboardGtk::setData): Write data to the DataObject and maybe the clipboard.
(WebCore::ClipboardGtk::types): Read the clipboard/DataObject to find applicable types.
(WebCore::ClipboardGtk::files): Read the clipboard/DataObject to find the files.
(WebCore::ClipboardGtk::writeURL): Write to the DataObject and maybe the clipboard.
(WebCore::ClipboardGtk::writeRange): Ditto.
(WebCore::ClipboardGtk::writePlainText): Ditto.
(WebCore::ClipboardGtk::hasData): Query the clipboard/DataObject.
* platform/gtk/ClipboardGtk.h:
(WebCore::ClipboardGtk::create): Added one factory for pasteboard-backed DataObjects and one for DnD-backed objects.
* platform/gtk/DataObjectGtk.cpp:
(WebCore::replaceNonBreakingSpaceWithSpace): Added this helper function to clean &nbsp; from plain text.
(WebCore::DataObjectGtk::markup): Actually return the range if it's set.
(WebCore::DataObjectGtk::setText): Clean &nbsp; from plain text.
(WebCore::DataObjectGtk::clearText): Added.
(WebCore::DataObjectGtk::clearMarkup): Added.
* platform/gtk/DataObjectGtk.h:
(WebCore::DataObjectGtk::clearURIList): Added.
(WebCore::DataObjectGtk::clearImage): Added.
* platform/gtk/PasteboardHelper.cpp:
(WebCore::PasteboardHelper::initializeTargetList): Added target ID's for URI list and Netscape URL targets.
(WebCore::urisToKURLVector): Added.
(WebCore::PasteboardHelper::getClipboardContents): Added.
(WebCore::PasteboardHelper::fillSelectionData): Added logic for URI lists and Netscape URLs.
(WebCore::PasteboardHelper::targetListForDataObject): Ditto.
* platform/gtk/PasteboardHelper.h: Added default argument to writeClipboardContents and new method.
2010-04-28 Martin Robinson <mrobinson@webkit.org>
 
Reviewed by Gustavo Noronha.
......@@ -24,6 +24,8 @@
#include "Frame.h"
#include "Image.h"
#include "NotImplemented.h"
#include "Pasteboard.h"
#include "PasteboardHelper.h"
#include "RenderImage.h"
#include "StringHash.h"
#include "markup.h"
......@@ -32,13 +34,33 @@
namespace WebCore {
enum ClipboardType {
ClipboardTypeText,
ClipboardTypeMarkup,
ClipboardTypeURIList,
ClipboardTypeURL,
ClipboardTypeImage,
ClipboardTypeUnknown
};
PassRefPtr<Clipboard> Editor::newGeneralClipboard(ClipboardAccessPolicy policy)
{
return ClipboardGtk::create(policy, false);
return ClipboardGtk::create(policy, gtk_clipboard_get_for_display(gdk_display_get_default(), GDK_SELECTION_CLIPBOARD), false);
}
ClipboardGtk::ClipboardGtk(ClipboardAccessPolicy policy, GtkClipboard* clipboard)
: Clipboard(policy, false)
, m_dataObject(DataObjectGtk::forClipboard(clipboard))
, m_clipboard(clipboard)
, m_helper(Pasteboard::generalPasteboard()->helper())
{
}
ClipboardGtk::ClipboardGtk(ClipboardAccessPolicy policy, bool forDragging)
ClipboardGtk::ClipboardGtk(ClipboardAccessPolicy policy, PassRefPtr<DataObjectGtk> dataObject, bool forDragging)
: Clipboard(policy, forDragging)
, m_dataObject(dataObject)
, m_clipboard(0)
, m_helper(Pasteboard::generalPasteboard()->helper())
{
}
......@@ -46,39 +68,197 @@ ClipboardGtk::~ClipboardGtk()
{
}
void ClipboardGtk::clearData(const String&)
static ClipboardType dataObjectTypeFromHTMLClipboardType(const String& rawType)
{
notImplemented();
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()
{
notImplemented();
if (policy() != ClipboardWritable)
return;
m_dataObject->clear();
if (m_clipboard)
m_helper->writeClipboardContents(m_clipboard);
}
String ClipboardGtk::getData(const String&, bool &success) const
static String joinURIList(Vector<KURL> uriList)
{
notImplemented();
success = false;
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&, const String&)
bool ClipboardGtk::setData(const String& typeString, const String& data)
{
notImplemented();
return false;
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
{
notImplemented();
return HashSet<String>();
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
{
notImplemented();
return 0;
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());
for (size_t i = 0; i < fileVector.size(); i++)
fileList->append(File::create(fileVector[i]));
return fileList.release();
}
IntPoint ClipboardGtk::dragLocation() const
......@@ -151,44 +331,54 @@ void ClipboardGtk::declareAndWriteDragImage(Element* element, const KURL& url, c
void ClipboardGtk::writeURL(const KURL& url, const String& label, Frame*)
{
GtkClipboard* textClipboard = gtk_clipboard_get(gdk_atom_intern_static_string("WebKitClipboardText"));
GtkClipboard* urlClipboard = gtk_clipboard_get(gdk_atom_intern_static_string("WebKitClipboardUrl"));
GtkClipboard* urlLabelClipboard = gtk_clipboard_get(gdk_atom_intern_static_string("WebKitClipboardUrlLabel"));
gtk_clipboard_clear(textClipboard);
gtk_clipboard_clear(urlClipboard);
gtk_clipboard_clear(urlLabelClipboard);
gtk_clipboard_set_text(textClipboard, url.string().utf8().data(), -1);
gtk_clipboard_set_text(urlClipboard, url.string().utf8().data(), -1);
gtk_clipboard_set_text(urlLabelClipboard, label.utf8().data(), -1);
String actualLabel(label);
if (actualLabel.isEmpty())
actualLabel = url;
m_dataObject->setText(url.string());
Vector<UChar> markup;
append(markup, "<a href=\"");
append(markup, url.string());
append(markup, "\">");
append(markup, label);
append(markup, "</a>");
m_dataObject->setMarkup(String::adopt(markup));
Vector<KURL> uriList;
uriList.append(url);
m_dataObject->setURIList(uriList);
if (m_clipboard)
m_helper->writeClipboardContents(m_clipboard);
}
void ClipboardGtk::writeRange(Range* range, Frame* frame)
{
GtkClipboard* textClipboard = gtk_clipboard_get(gdk_atom_intern_static_string("WebKitClipboardText"));
GtkClipboard* htmlClipboard = gtk_clipboard_get(gdk_atom_intern_static_string("WebKitClipboardHtml"));
ASSERT(range);
gtk_clipboard_clear(textClipboard);
gtk_clipboard_clear(htmlClipboard);
m_dataObject->setText(frame->selectedText());
m_dataObject->setMarkup(createMarkup(range, 0, AnnotateForInterchange));
gtk_clipboard_set_text(textClipboard, frame->selectedText().utf8().data(), -1);
gtk_clipboard_set_text(htmlClipboard, createMarkup(range, 0, AnnotateForInterchange).utf8().data(), -1);
if (m_clipboard)
m_helper->writeClipboardContents(m_clipboard);
}
void ClipboardGtk::writePlainText(const String& text)
{
GtkClipboard* textClipboard = gtk_clipboard_get(gdk_atom_intern_static_string("WebKitClipboardText"));
gtk_clipboard_clear(textClipboard);
gtk_clipboard_set_text(textClipboard, text.utf8().data(), -1);
m_dataObject->setText(text);
if (m_clipboard)
m_helper->writeClipboardContents(m_clipboard);
}
bool ClipboardGtk::hasData()
{
notImplemented();
return false;
if (m_clipboard)
m_helper->getClipboardContents(m_clipboard);
return m_dataObject->hasText() || m_dataObject->hasMarkup()
|| m_dataObject->hasURIList() || m_dataObject->hasImage();
}
}
......@@ -28,17 +28,26 @@
#define ClipboardGtk_h
#include "Clipboard.h"
#include "DataObjectGtk.h"
typedef struct _GtkClipboard GtkClipboard;
namespace WebCore {
class CachedImage;
class PasteboardHelper;
// State available during IE's events for drag and drop and copy/paste
// Created from the EventHandlerGtk to be used by the dom
class ClipboardGtk : public Clipboard {
public:
static PassRefPtr<ClipboardGtk> create(ClipboardAccessPolicy policy, GtkClipboard* clipboard, bool isForDragging)
{
return adoptRef(new ClipboardGtk(policy, clipboard));
}
static PassRefPtr<ClipboardGtk> create(ClipboardAccessPolicy policy, bool isForDragging)
{
return adoptRef(new ClipboardGtk(policy, isForDragging));
return adoptRef(new ClipboardGtk(policy, DataObjectGtk::create(), isForDragging));
}
virtual ~ClipboardGtk();
......@@ -65,7 +74,12 @@ namespace WebCore {
virtual bool hasData();
private:
ClipboardGtk(ClipboardAccessPolicy, bool);
ClipboardGtk(ClipboardAccessPolicy, GtkClipboard*);
ClipboardGtk(ClipboardAccessPolicy, PassRefPtr<DataObjectGtk>, bool);
RefPtr<DataObjectGtk> m_dataObject;
GtkClipboard* m_clipboard;
PasteboardHelper* m_helper;
};
}
......
......@@ -24,6 +24,13 @@
namespace WebCore {
static void replaceNonBreakingSpaceWithSpace(String& str)
{
static const UChar NonBreakingSpaceCharacter = 0xA0;
static const UChar SpaceCharacter = ' ';
str.replace(NonBreakingSpaceCharacter, SpaceCharacter);
}
String DataObjectGtk::text()
{
if (m_range)
......@@ -34,7 +41,7 @@ String DataObjectGtk::text()
String DataObjectGtk::markup()
{
if (m_range)
createMarkup(m_range.get(), 0, AnnotateForInterchange);
return createMarkup(m_range.get(), 0, AnnotateForInterchange);
return m_markup;
}
......@@ -42,6 +49,7 @@ void DataObjectGtk::setText(const String& newText)
{
m_range = 0;
m_text = newText;
replaceNonBreakingSpaceWithSpace(m_text);
}
void DataObjectGtk::setMarkup(const String& newMarkup)
......@@ -50,6 +58,18 @@ void DataObjectGtk::setMarkup(const String& newMarkup)
m_markup = newMarkup;
}
void DataObjectGtk::clearText()
{
m_range = 0;
m_text = "";
}
void DataObjectGtk::clearMarkup()
{
m_range = 0;
m_markup = "";
}
Vector<String> DataObjectGtk::files()
{
Vector<KURL> uris(uriList());
......
......@@ -50,6 +50,8 @@ public:
bool hasMarkup() { return m_range || !m_markup.isEmpty(); }
bool hasURIList() { return !m_uriList.isEmpty(); }
bool hasImage() { return m_image; }
void clearURIList() { m_uriList.clear(); }
void clearImage() { m_image = 0; }
GdkDragContext* dragContext() { return m_dragContext.get(); }
String text();
......@@ -61,6 +63,8 @@ public:
String url();
String urlLabel();
void clear();
void clearText();
void clearMarkup();
static DataObjectGtk* forClipboard(GtkClipboard*);
......
......@@ -26,12 +26,15 @@
#include "Frame.h"
#include "Page.h"
#include "Pasteboard.h"
#include "TextResourceDecoder.h"
#include <gtk/gtk.h>
#include <wtf/gobject/GOwnPtr.h>
namespace WebCore {
static GdkAtom gdkMarkupAtom = gdk_atom_intern("text/html", FALSE);
static GdkAtom netscapeURLAtom = gdk_atom_intern("_NETSCAPE_URL", FALSE);
static GdkAtom uriListAtom = gdk_atom_intern("text/uri-list", FALSE);
PasteboardHelper::PasteboardHelper()
: m_targetList(gtk_target_list_new(0, 0))
......@@ -48,6 +51,8 @@ void PasteboardHelper::initializeTargetList()
{
gtk_target_list_add_text_targets(m_targetList, getIdForTargetType(TargetTypeText));
gtk_target_list_add(m_targetList, gdkMarkupAtom, 0, getIdForTargetType(TargetTypeMarkup));
gtk_target_list_add_uri_targets(m_targetList, getIdForTargetType(TargetTypeURIList));
gtk_target_list_add(m_targetList, netscapeURLAtom, 0, getIdForTargetType(TargetTypeNetscapeURL));
}
static inline GtkWidget* widgetFromFrame(Frame* frame)
......@@ -84,15 +89,82 @@ GtkTargetList* PasteboardHelper::targetList() const
return m_targetList;
}
static Vector<KURL> urisToKURLVector(gchar** uris)
{
ASSERT(uris);
Vector<KURL> uriList;
for (int i = 0; *(uris + i); i++)
uriList.append(KURL(KURL(), *(uris + i)));
return uriList;
}
void PasteboardHelper::getClipboardContents(GtkClipboard* clipboard)
{
DataObjectGtk* dataObject = DataObjectGtk::forClipboard(clipboard);
ASSERT(dataObject);
if (gtk_clipboard_wait_is_text_available(clipboard)) {
GOwnPtr<gchar> textData(gtk_clipboard_wait_for_text(clipboard));
if (textData)
dataObject->setText(String::fromUTF8(textData.get()));
}
if (gtk_clipboard_wait_is_target_available(clipboard, gdkMarkupAtom)) {
if (GtkSelectionData* data = gtk_clipboard_wait_for_contents(clipboard, gdkMarkupAtom)) {
RefPtr<TextResourceDecoder> decoder(TextResourceDecoder::create("text/plain", "UTF-8", true));
String markup(decoder->decode(reinterpret_cast<char*>(data->data), data->length));
markup += decoder->flush();
dataObject->setMarkup(markup);
gtk_selection_data_free(data);
}
}
if (gtk_clipboard_wait_is_target_available(clipboard, uriListAtom)) {
if (GtkSelectionData* data = gtk_clipboard_wait_for_contents(clipboard, uriListAtom)) {
gchar** uris = gtk_selection_data_get_uris(data);
if (uris) {
dataObject->setURIList(urisToKURLVector(uris));
g_strfreev(uris);
}
gtk_selection_data_free(data);
}
}
}
void PasteboardHelper::fillSelectionData(GtkSelectionData* selectionData, guint info, DataObjectGtk* dataObject)
{