Source/WebCore: WebKit2: add support for drag and drop on Windows
authorenrica@apple.com <enrica@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 27 Jan 2011 19:51:14 +0000 (19:51 +0000)
committerenrica@apple.com <enrica@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 27 Jan 2011 19:51:14 +0000 (19:51 +0000)
https://bugs.webkit.org/show_bug.cgi?id=52775
<rdar://problem/8514409>

Reviewed by Darin Adler and Adam Roben.

On Windows the access to the content being dragged is
provided via the IDataObject interface that is made available
to the window that registers itself as drop target.
Since this interface cannot be accessed from the WebProcess,
in every call to one of the methods of the IDropTarget interface
we serialize the content of the drag clipboard and send it over to
the WebProcess.
The bulk of this patch consists in the refactoring needed in DragData
and ClipboardWin classes to extract the data from the serialized object.

* platform/DragData.cpp:
* platform/DragData.h:
* platform/win/ClipboardUtilitiesWin.cpp:
(WebCore::getWebLocData):
(WebCore::getURL):
(WebCore::getPlainText):
(WebCore::getTextHTML):
(WebCore::getCFHTML):
(WebCore::fragmentFromFilenames):
(WebCore::containsFilenames):
(WebCore::fragmentFromHTML):
(WebCore::containsHTML):
(WebCore::getClipboardData):
* platform/win/ClipboardUtilitiesWin.h:
* platform/win/ClipboardWin.cpp:
(WebCore::Clipboard::create):
(WebCore::ClipboardWin::ClipboardWin):
(WebCore::ClipboardWin::getData):
(WebCore::ClipboardWin::types):
(WebCore::ClipboardWin::files):
(WebCore::ClipboardWin::hasData):
* platform/win/ClipboardWin.h:
(WebCore::ClipboardWin::create):
* platform/win/DragDataWin.cpp:
(WebCore::DragData::DragData):
(WebCore::DragData::containsURL):
(WebCore::DragData::dragDataMap):
(WebCore::DragData::asURL):
(WebCore::DragData::containsFiles):
(WebCore::DragData::asFilenames):
(WebCore::DragData::containsPlainText):
(WebCore::DragData::asPlainText):
(WebCore::DragData::canSmartReplace):
(WebCore::DragData::containsCompatibleContent):
(WebCore::DragData::asFragment):

Source/WebKit2: WebKit2: add support for drag and drop on Windows
https://bugs.webkit.org/show_bug.cgi?id=52775
<rdar://problem/8514409>

Reviewed by Darin Adler and Adam Roben.

On Windows the access to the content being dragged is
provided via the IDataObject interface that is made available
to the window that registers itself as drop target.
Since this interface cannot be accessed from the WebProcess,
in every call to one of the methods of the IDropTarget interface
we serialize the content of the drag clipboard and send it over to
the WebProcess. The implementation uses the same messages as the
Mac one, with slightly different parameters to pass the serialized
clipboard.

* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::performDragControllerAction): Added Windows
specific implementation.
* UIProcess/WebPageProxy.h:
* UIProcess/win/WebView.cpp:
(WebKit::WebView::WebView): Added dropTargetHelper object creation.
(WebKit::WebView::initialize): Added to register for drag/drop with out
refcount issues.
(WebKit::WebView::close):
(WebKit::WebView::windowReceivedMessage):
(WebKit::WebView::QueryInterface):
(WebKit::WebView::AddRef):
(WebKit::WebView::Release):
(WebKit::dragOperationToDragCursor):
(WebKit::WebView::keyStateToDragOperation):
(WebKit::WebView::DragEnter):
(WebKit::WebView::DragOver):
(WebKit::WebView::DragLeave):
(WebKit::WebView::Drop):
* UIProcess/win/WebView.h:
(WebKit::WebView::create):
* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::performDragControllerAction):
* WebProcess/WebPage/WebPage.h:
* WebProcess/WebPage/WebPage.messages.in:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@76824 268f45cc-cd09-0410-ab3c-d52691b4dbfc

15 files changed:
Source/WebCore/ChangeLog
Source/WebCore/platform/DragData.h
Source/WebCore/platform/win/ClipboardUtilitiesWin.cpp
Source/WebCore/platform/win/ClipboardUtilitiesWin.h
Source/WebCore/platform/win/ClipboardWin.cpp
Source/WebCore/platform/win/ClipboardWin.h
Source/WebCore/platform/win/DragDataWin.cpp
Source/WebKit2/ChangeLog
Source/WebKit2/UIProcess/WebPageProxy.cpp
Source/WebKit2/UIProcess/WebPageProxy.h
Source/WebKit2/UIProcess/win/WebView.cpp
Source/WebKit2/UIProcess/win/WebView.h
Source/WebKit2/WebProcess/WebPage/WebPage.cpp
Source/WebKit2/WebProcess/WebPage/WebPage.h
Source/WebKit2/WebProcess/WebPage/WebPage.messages.in

index 10715dc..6c686df 100644 (file)
@@ -1,3 +1,57 @@
+2011-01-26  Enrica Casucci  <enrica@apple.com>
+
+        Reviewed by Darin Adler and Adam Roben.
+
+        WebKit2: add support for drag and drop on Windows
+        https://bugs.webkit.org/show_bug.cgi?id=52775
+        <rdar://problem/8514409>
+        
+        On Windows the access to the content being dragged is
+        provided via the IDataObject interface that is made available
+        to the window that registers itself as drop target.
+        Since this interface cannot be accessed from the WebProcess,
+        in every call to one of the methods of the IDropTarget interface
+        we serialize the content of the drag clipboard and send it over to
+        the WebProcess.
+        The bulk of this patch consists in the refactoring needed in DragData
+        and ClipboardWin classes to extract the data from the serialized object.
+        
+        * platform/DragData.cpp:
+        * platform/DragData.h:
+        * platform/win/ClipboardUtilitiesWin.cpp:
+        (WebCore::getWebLocData):
+        (WebCore::getURL):
+        (WebCore::getPlainText):
+        (WebCore::getTextHTML):
+        (WebCore::getCFHTML):
+        (WebCore::fragmentFromFilenames):
+        (WebCore::containsFilenames):
+        (WebCore::fragmentFromHTML):
+        (WebCore::containsHTML):
+        (WebCore::getClipboardData):
+        * platform/win/ClipboardUtilitiesWin.h:
+        * platform/win/ClipboardWin.cpp:
+        (WebCore::Clipboard::create):
+        (WebCore::ClipboardWin::ClipboardWin):
+        (WebCore::ClipboardWin::getData):
+        (WebCore::ClipboardWin::types):
+        (WebCore::ClipboardWin::files):
+        (WebCore::ClipboardWin::hasData):
+        * platform/win/ClipboardWin.h:
+        (WebCore::ClipboardWin::create):
+        * platform/win/DragDataWin.cpp:
+        (WebCore::DragData::DragData):
+        (WebCore::DragData::containsURL):
+        (WebCore::DragData::dragDataMap):
+        (WebCore::DragData::asURL):
+        (WebCore::DragData::containsFiles):
+        (WebCore::DragData::asFilenames):
+        (WebCore::DragData::containsPlainText):
+        (WebCore::DragData::asPlainText):
+        (WebCore::DragData::canSmartReplace):
+        (WebCore::DragData::containsCompatibleContent):
+        (WebCore::DragData::asFragment):
+
 2011-01-27  Mario Sanchez Prada  <msanchez@igalia.com>
 
         Reviewed by Martin Robinson.
index 791b7ce..5542659 100644 (file)
@@ -31,6 +31,7 @@
 #include "IntPoint.h"
 
 #include <wtf/Forward.h>
+#include <wtf/HashMap.h>
 #include <wtf/Vector.h>
 
 #if PLATFORM(MAC)
@@ -51,6 +52,7 @@ QT_END_NAMESPACE
 typedef const QMimeData* DragDataRef;
 #elif PLATFORM(WIN)
 typedef struct IDataObject* DragDataRef;
+#include <wtf/text/WTFString.h>
 #elif PLATFORM(WX)
 typedef class wxDataObject* DragDataRef;
 #elif PLATFORM(GTK)
@@ -82,7 +84,11 @@ enum DragApplicationFlags {
     DragApplicationHasAttachedSheet = 4,
     DragApplicationIsCopyKeyDown = 8
 };
-    
+
+#if PLATFORM(WIN)
+typedef HashMap<UINT, Vector<String> > DragDataMap;
+#endif
+
 class DragData {
 public:
     enum FilenameConversionPolicy { DoNotConvertFilenames, ConvertFilenames };
@@ -90,7 +96,10 @@ public:
     // clientPosition is taken to be the position of the drag event within the target window, with (0,0) at the top left
     DragData(DragDataRef, const IntPoint& clientPosition, const IntPoint& globalPosition, DragOperation, DragApplicationFlags = DragApplicationNone);
     DragData(const String& dragStorageName, const IntPoint& clientPosition, const IntPoint& globalPosition, DragOperation, DragApplicationFlags = DragApplicationNone);
-
+#if PLATFORM(WIN)
+    DragData(const DragDataMap&, const IntPoint& clientPosition, const IntPoint& globalPosition, DragOperation sourceOperationMask, DragApplicationFlags = DragApplicationNone);
+    const DragDataMap& dragDataMap();
+#endif
     const IntPoint& clientPosition() const { return m_clientPosition; }
     const IntPoint& globalPosition() const { return m_globalPosition; }
     DragApplicationFlags flags() { return m_applicationFlags; }
@@ -117,6 +126,9 @@ private:
 #if PLATFORM(MAC)
     RetainPtr<NSPasteboard> m_pasteboard;
 #endif
+#if PLATFORM(WIN)
+    DragDataMap m_dragDataMap;
+#endif
 };
     
 }
index eb1e659..629ad99 100644 (file)
@@ -70,6 +70,15 @@ static bool urlFromPath(CFStringRef path, String& url)
 }
 #endif
 
+static bool getDataMapItem(const DragDataMap* dataObject, FORMATETC* format, String& item)
+{
+    DragDataMap::const_iterator found = dataObject->find(format->cfFormat);
+    if (found == dataObject->end())
+        return false;
+    item = found->second[0];
+    return true;
+}
+
 static bool getWebLocData(IDataObject* dataObject, String& url, String* title) 
 {
     bool succeeded = false;
@@ -111,6 +120,34 @@ exit:
     return succeeded;
 }
 
+static bool getWebLocData(const DragDataMap* dataObject, String& url, String* title) 
+{
+#if PLATFORM(CF)
+    WCHAR filename[MAX_PATH];
+    WCHAR urlBuffer[INTERNET_MAX_URL_LENGTH];
+
+    if (!dataObject->contains(cfHDropFormat()->cfFormat))
+        return false;
+
+    wcscpy(filename, dataObject->get(cfHDropFormat()->cfFormat)[0].characters());
+    if (_wcsicmp(PathFindExtensionW(filename), L".url"))
+        return false;    
+
+    if (!GetPrivateProfileStringW(L"InternetShortcut", L"url", 0, urlBuffer, WTF_ARRAY_LENGTH(urlBuffer), filename))
+        return false;
+
+    if (title) {
+        PathRemoveExtension(filename);
+        *title = filename;
+    }
+    
+    url = urlBuffer;
+    return true;
+#else
+    return false;
+#endif
+}
+
 static String extractURL(const String &inURL, String* title)
 {
     String url = inURL;
@@ -386,6 +423,33 @@ String getURL(IDataObject* dataObject, DragData::FilenameConversionPolicy filena
     return url;
 }
 
+String getURL(const DragDataMap* data, DragData::FilenameConversionPolicy filenamePolicy, String* title)
+{
+    String url;
+
+    if (getWebLocData(data, url, title))
+        return url;
+    if (getDataMapItem(data, urlWFormat(), url))
+        return extractURL(url, title);
+    if (getDataMapItem(data, urlFormat(), url))
+        return extractURL(url, title);
+#if PLATFORM(CF)
+    if (filenamePolicy != DragData::ConvertFilenames)
+        return url;
+
+    String stringData;
+    if (!getDataMapItem(data, filenameWFormat(), stringData))
+        getDataMapItem(data, filenameFormat(), stringData);
+
+    if (stringData.isEmpty() || (!PathFileExists(stringData.charactersWithNullTermination()) && !PathIsUNC(stringData.charactersWithNullTermination())))
+        return url;
+    RetainPtr<CFStringRef> pathAsCFString(AdoptCF, CFStringCreateWithCharacters(kCFAllocatorDefault, (const UniChar *)stringData.charactersWithNullTermination(), stringData.length()));
+    if (urlFromPath(pathAsCFString.get(), url) && title)
+        *title = url;
+#endif
+    return url;
+}
+
 String getPlainText(IDataObject* dataObject, bool& success)
 {
     STGMEDIUM store;
@@ -415,6 +479,17 @@ String getPlainText(IDataObject* dataObject, bool& success)
     return text;
 }
 
+String getPlainText(const DragDataMap* data)
+{
+    String text;
+    
+    if (getDataMapItem(data, plainTextWFormat(), text))
+        return text;
+    if (getDataMapItem(data, plainTextFormat(), text))
+        return text;
+    return getURL(data, DragData::DoNotConvertFilenames);
+}
+
 String getTextHTML(IDataObject* data, bool& success)
 {
     STGMEDIUM store;
@@ -430,6 +505,13 @@ String getTextHTML(IDataObject* data, bool& success)
     return html;
 }
 
+String getTextHTML(const DragDataMap* data)
+{
+    String text;
+    getDataMapItem(data, texthtmlFormat(), text);
+    return text;
+}
+
 String getCFHTML(IDataObject* data, bool& success)
 {
     String cfhtml = getFullCFHTML(data, success);
@@ -438,18 +520,37 @@ String getCFHTML(IDataObject* data, bool& success)
     return String();
 }
 
+String getCFHTML(const DragDataMap* dataMap)
+{
+    String cfhtml;
+    getDataMapItem(dataMap, htmlFormat(), cfhtml);
+    return extractMarkupFromCFHTML(cfhtml);
+}
+
 PassRefPtr<DocumentFragment> fragmentFromFilenames(Document*, const IDataObject*)
 {
     // FIXME: We should be able to create fragments from files
     return 0;
 }
 
+PassRefPtr<DocumentFragment> fragmentFromFilenames(Document*, const DragDataMap*)
+{
+    // FIXME: We should be able to create fragments from files
+    return 0;
+}
+
 bool containsFilenames(const IDataObject*)
 {
     // FIXME: We'll want to update this once we can produce fragments from files
     return false;
 }
 
+bool containsFilenames(const DragDataMap*)
+{
+    // FIXME: We'll want to update this once we can produce fragments from files
+    return false;
+}
+
 // Convert a String containing CF_HTML formatted text to a DocumentFragment
 PassRefPtr<DocumentFragment> fragmentFromCFHTML(Document* doc, const String& cfhtml)
 {
@@ -477,8 +578,8 @@ PassRefPtr<DocumentFragment> fragmentFromHTML(Document* doc, IDataObject* data)
     bool success = false;
     String cfhtml = getFullCFHTML(data, success);
     if (success) {
-        if (PassRefPtr<DocumentFragment> fragment = fragmentFromCFHTML(doc, cfhtml))
-            return fragment;
+        if (RefPtr<DocumentFragment> fragment = fragmentFromCFHTML(doc, cfhtml))
+            return fragment.release();
     }
 
     String html = getTextHTML(data, success);
@@ -489,9 +590,101 @@ PassRefPtr<DocumentFragment> fragmentFromHTML(Document* doc, IDataObject* data)
     return 0;
 }
 
+PassRefPtr<DocumentFragment> fragmentFromHTML(Document* document, const DragDataMap* data) 
+{
+    if (!document || !data || data->isEmpty())
+        return 0;
+
+    String stringData;
+    if (getDataMapItem(data, htmlFormat(), stringData)) {
+        if (RefPtr<DocumentFragment> fragment = fragmentFromCFHTML(document, stringData))
+            return fragment.release();
+    }
+
+    String srcURL;
+    if (getDataMapItem(data, texthtmlFormat(), stringData))
+        return createFragmentFromMarkup(document, stringData, srcURL, FragmentScriptingNotAllowed);
+
+    return 0;
+}
+
 bool containsHTML(IDataObject* data)
 {
     return SUCCEEDED(data->QueryGetData(texthtmlFormat())) || SUCCEEDED(data->QueryGetData(htmlFormat()));
 }
 
+bool containsHTML(const DragDataMap* data)
+{
+    return data->contains(texthtmlFormat()->cfFormat) || data->contains(htmlFormat()->cfFormat);
+}
+
+typedef void (*GetStringFunction)(IDataObject*, FORMATETC*, Vector<String>&);
+typedef HashMap<UINT, GetStringFunction> ClipboardFormatMap;
+
+template<typename T> void getStringData(IDataObject* data, FORMATETC* format, Vector<String>& dataStrings)
+{
+    STGMEDIUM store;
+    if (FAILED(data->GetData(format, &store)))
+        return;
+    dataStrings.append(String(static_cast<T*>(GlobalLock(store.hGlobal)), ::GlobalSize(store.hGlobal) / sizeof(T)));
+    GlobalUnlock(store.hGlobal);
+    ReleaseStgMedium(&store);
+}
+
+void getUtf8Data(IDataObject* data, FORMATETC* format, Vector<String>& dataStrings)
+{
+    STGMEDIUM store;
+    if (FAILED(data->GetData(format, &store)))
+        return;
+    dataStrings.append(String(UTF8Encoding().decode(static_cast<char*>(GlobalLock(store.hGlobal)), GlobalSize(store.hGlobal))));
+    GlobalUnlock(store.hGlobal);
+    ReleaseStgMedium(&store);
+}
+
+#if PLATFORM(CF)
+void getCfData(IDataObject* data, FORMATETC* format, Vector<String>& dataStrings)
+{
+    STGMEDIUM store;
+    if (FAILED(data->GetData(format, &store)))
+        return;
+
+    HDROP hdrop = reinterpret_cast<HDROP>(GlobalLock(store.hGlobal));
+    if (!hdrop)
+        return;
+
+    WCHAR filename[MAX_PATH];
+    UINT fileCount = DragQueryFileW(hdrop, 0xFFFFFFFF, 0, 0);
+    for (UINT i = 0; i < fileCount; i++) {
+        if (!DragQueryFileW(hdrop, i, filename, WTF_ARRAY_LENGTH(filename)))
+            continue;
+        dataStrings.append(static_cast<UChar*>(filename));
+    }
+
+    GlobalUnlock(store.hGlobal);
+    ReleaseStgMedium(&store);
+}
+#endif
+
+void getClipboardData(IDataObject *dataObject, FORMATETC* format, Vector<String>& dataStrings)
+{
+    static ClipboardFormatMap formatMap;
+    if (formatMap.isEmpty()) {
+        formatMap.add(htmlFormat()->cfFormat, getUtf8Data);
+        formatMap.add(texthtmlFormat()->cfFormat, getStringData<UChar>);
+        formatMap.add(plainTextFormat()->cfFormat, getStringData<char>);
+        formatMap.add(plainTextWFormat()->cfFormat, getStringData<UChar>);
+#if PLATFORM(CF)
+        formatMap.add(cfHDropFormat()->cfFormat, getCfData);
+#endif
+        formatMap.add(filenameFormat()->cfFormat, getStringData<char>);
+        formatMap.add(filenameWFormat()->cfFormat, getStringData<UChar>);
+        formatMap.add(urlFormat()->cfFormat, getStringData<char>);
+        formatMap.add(urlWFormat()->cfFormat, getStringData<UChar>);
+    }
+    ClipboardFormatMap::iterator found = formatMap.find(format->cfFormat);
+    if (found == formatMap.end())
+        return;
+    found->second(dataObject, format, dataStrings);
+}
+
 } // namespace WebCore
index 1a29e7e..d1362b3 100644 (file)
@@ -55,16 +55,26 @@ void replaceNewlinesWithWindowsStyleNewlines(String&);
 void replaceNBSPWithSpace(String&);
 
 bool containsFilenames(const IDataObject*);
+bool containsFilenames(const DragDataMap*);
 bool containsHTML(IDataObject*);
+bool containsHTML(const DragDataMap*);
 
 PassRefPtr<DocumentFragment> fragmentFromFilenames(Document*, const IDataObject*);
+PassRefPtr<DocumentFragment> fragmentFromFilenames(Document*, const DragDataMap*);
 PassRefPtr<DocumentFragment> fragmentFromHTML(Document*, IDataObject*);
+PassRefPtr<DocumentFragment> fragmentFromHTML(Document*, const DragDataMap*);
 PassRefPtr<DocumentFragment> fragmentFromCFHTML(Document*, const String& cfhtml);
 
 String getURL(IDataObject*, DragData::FilenameConversionPolicy, bool& success, String* title = 0);
+String getURL(const DragDataMap*, DragData::FilenameConversionPolicy, String* title = 0);
 String getPlainText(IDataObject*, bool& success);
+String getPlainText(const DragDataMap*);
 String getTextHTML(IDataObject*, bool& success);
+String getTextHTML(const DragDataMap*);
 String getCFHTML(IDataObject*, bool& success);
+String getCFHTML(const DragDataMap*);
+
+void getClipboardData(IDataObject*, FORMATETC* fetc, Vector<String>& dataStrings);
 
 } // namespace WebCore
 
index 58cfe44..0624fb7 100644 (file)
@@ -340,7 +340,9 @@ exit:
 
 PassRefPtr<Clipboard> Clipboard::create(ClipboardAccessPolicy policy, DragData* dragData, Frame* frame)
 {
-    return ClipboardWin::create(DragAndDrop, dragData->platformData(), policy, frame);
+    if (dragData->platformData())
+        return ClipboardWin::create(DragAndDrop, dragData->platformData(), policy, frame);
+    return ClipboardWin::create(DragAndDrop, dragData->dragDataMap(), policy, frame);
 }
 
 ClipboardWin::ClipboardWin(ClipboardType clipboardType, IDataObject* dataObject, ClipboardAccessPolicy policy, Frame* frame)
@@ -359,6 +361,15 @@ ClipboardWin::ClipboardWin(ClipboardType clipboardType, WCDataObject* dataObject
 {
 }
 
+ClipboardWin::ClipboardWin(ClipboardType clipboardType, const DragDataMap& dataMap, ClipboardAccessPolicy policy, Frame* frame)
+    : Clipboard(policy, clipboardType)
+    , m_dataObject(0)
+    , m_writableDataObject(0)
+    , m_frame(frame)
+    , m_dragDataMap(dataMap)
+{
+}
+
 ClipboardWin::~ClipboardWin()
 {
 }
@@ -442,19 +453,19 @@ void ClipboardWin::clearAllData()
 String ClipboardWin::getData(const String& type, bool& success) const
 {     
     success = false;
-    if (policy() != ClipboardReadable || !m_dataObject)
+    if (policy() != ClipboardReadable || !m_dataObject || m_dragDataMap.isEmpty())
         return "";
 
     ClipboardDataType dataType = clipboardTypeFromMIMEType(type);
     if (dataType == ClipboardDataTypeText)
-        return getPlainText(m_dataObject.get(), success);
+        return m_dataObject ? getPlainText(m_dataObject.get(), success) : getPlainText(&m_dragDataMap);
     if (dataType == ClipboardDataTypeURL)
-        return getURL(m_dataObject.get(), DragData::DoNotConvertFilenames, success);
+        return m_dataObject ? getURL(m_dataObject.get(), DragData::DoNotConvertFilenames, success) : getURL(&m_dragDataMap, DragData::DoNotConvertFilenames);
     else if (dataType == ClipboardDataTypeTextHTML) {
-        String data = getTextHTML(m_dataObject.get(), success);
+        String data = m_dataObject ? getTextHTML(m_dataObject.get(), success) : getTextHTML(&m_dragDataMap);
         if (success)
             return data;
-        return getCFHTML(m_dataObject.get(), success);
+        return m_dataObject ? getCFHTML(m_dataObject.get(), success) : getCFHTML(&m_dragDataMap);
     }
     
     return "";
@@ -510,22 +521,30 @@ HashSet<String> ClipboardWin::types() const
     if (policy() != ClipboardReadable && policy() != ClipboardTypesReadable)
         return results;
 
-    if (!m_dataObject)
+    if (!m_dataObject || m_dragDataMap.isEmpty())
         return results;
 
-    COMPtr<IEnumFORMATETC> itr;
+    if (m_dataObject) {
+        COMPtr<IEnumFORMATETC> itr;
 
-    if (FAILED(m_dataObject->EnumFormatEtc(DATADIR_GET, &itr)))
-        return results;
+        if (FAILED(m_dataObject->EnumFormatEtc(DATADIR_GET, &itr)))
+            return results;
 
-    if (!itr)
-        return results;
+        if (!itr)
+            return results;
 
-    FORMATETC data;
+        FORMATETC data;
 
-    // IEnumFORMATETC::Next returns S_FALSE if there are no more items.
-    while (itr->Next(1, &data, 0) == S_OK)
-        addMimeTypesForFormat(results, data);
+        // IEnumFORMATETC::Next returns S_FALSE if there are no more items.
+        while (itr->Next(1, &data, 0) == S_OK)
+            addMimeTypesForFormat(results, data);
+    } else {
+        for (DragDataMap::const_iterator it = m_dragDataMap.begin(); it != m_dragDataMap.end(); ++it) {
+            FORMATETC data;
+            data.cfFormat = (*it).first;
+            addMimeTypesForFormat(results, data);
+        }
+    }
 
     return results;
 }
@@ -540,27 +559,35 @@ PassRefPtr<FileList> ClipboardWin::files() const
     if (policy() != ClipboardReadable && policy() != ClipboardTypesReadable)
         return files.release();
 
-    if (!m_dataObject)
+    if (!m_dataObject || m_dragDataMap.isEmpty())
         return files.release();
 
-    STGMEDIUM medium;
-    if (FAILED(m_dataObject->GetData(cfHDropFormat(), &medium)))
-        return files.release();
+    if (m_dataObject) {
+        STGMEDIUM medium;
+        if (FAILED(m_dataObject->GetData(cfHDropFormat(), &medium)))
+            return files.release();
+
+        HDROP hdrop = reinterpret_cast<HDROP>(GlobalLock(medium.hGlobal));
+        if (!hdrop)
+            return files.release();
+
+        WCHAR filename[MAX_PATH];
+        UINT fileCount = DragQueryFileW(hdrop, 0xFFFFFFFF, 0, 0);
+        for (UINT i = 0; i < fileCount; i++) {
+            if (!DragQueryFileW(hdrop, i, filename, WTF_ARRAY_LENGTH(filename)))
+                continue;
+            files->append(File::create(reinterpret_cast<UChar*>(filename)));
+        }
 
-    HDROP hdrop = reinterpret_cast<HDROP>(GlobalLock(medium.hGlobal));
-    if (!hdrop)
+        GlobalUnlock(medium.hGlobal);
+        ReleaseStgMedium(&medium);
         return files.release();
-
-    WCHAR filename[MAX_PATH];
-    UINT fileCount = DragQueryFileW(hdrop, 0xFFFFFFFF, 0, 0);
-    for (UINT i = 0; i < fileCount; i++) {
-        if (!DragQueryFileW(hdrop, i, filename, WTF_ARRAY_LENGTH(filename)))
-            continue;
-        files->append(File::create(reinterpret_cast<UChar*>(filename)));
     }
-
-    GlobalUnlock(medium.hGlobal);
-    ReleaseStgMedium(&medium);
+    if (!m_dragDataMap.contains(cfHDropFormat()->cfFormat))
+        return files.release();
+    Vector<String> filesVector = m_dragDataMap.get(cfHDropFormat()->cfFormat);
+    for (Vector<String>::iterator it = filesVector.begin(); it != filesVector.end(); ++it)
+        files->append(File::create((*it).characters()));
     return files.release();
 #endif
 }
@@ -778,25 +805,28 @@ void ClipboardWin::writePlainText(const String& text)
     
 bool ClipboardWin::hasData()
 {
-    if (!m_dataObject)
+    if (!m_dataObject && m_dragDataMap.isEmpty())
         return false;
 
-    COMPtr<IEnumFORMATETC> itr;
-    if (FAILED(m_dataObject->EnumFormatEtc(DATADIR_GET, &itr)))
-        return false;
+    if (m_dataObject) {
+        COMPtr<IEnumFORMATETC> itr;
+        if (FAILED(m_dataObject->EnumFormatEtc(DATADIR_GET, &itr)))
+            return false;
 
-    if (!itr)
-        return false;
+        if (!itr)
+            return false;
 
-    FORMATETC data;
+        FORMATETC data;
 
-    // IEnumFORMATETC::Next returns S_FALSE if there are no more items.
-    if (itr->Next(1, &data, 0) == S_OK) {
-        // There is at least one item in the IDataObject
-        return true;
-    }
+        // IEnumFORMATETC::Next returns S_FALSE if there are no more items.
+        if (itr->Next(1, &data, 0) == S_OK) {
+            // There is at least one item in the IDataObject
+            return true;
+        }
 
-    return false;
+        return false;
+    }
+    return !m_dragDataMap.isEmpty();
 }
 
 void ClipboardWin::setExternalDataObject(IDataObject *dataObject)
index 779da26..7530eeb 100644 (file)
@@ -29,6 +29,7 @@
 #include "COMPtr.h"
 #include "CachedResourceClient.h"
 #include "Clipboard.h"
+#include "DragData.h"
 
 struct IDataObject;
 
@@ -51,6 +52,10 @@ public:
     {
         return adoptRef(new ClipboardWin(clipboardType, dataObject, policy, frame));
     }
+    static PassRefPtr<ClipboardWin> create(ClipboardType clipboardType, const DragDataMap& dataMap, ClipboardAccessPolicy policy, Frame* frame)
+    {
+        return adoptRef(new ClipboardWin(clipboardType, dataMap, policy, frame));
+    }
     ~ClipboardWin();
 
     void clearData(const String& type);
@@ -80,12 +85,14 @@ public:
 private:
     ClipboardWin(ClipboardType, IDataObject*, ClipboardAccessPolicy, Frame*);
     ClipboardWin(ClipboardType, WCDataObject*, ClipboardAccessPolicy, Frame*);
+    ClipboardWin(ClipboardType, const DragDataMap&, ClipboardAccessPolicy, Frame*);
 
     void resetFromClipboard();
     void setDragImage(CachedImage*, Node*, const IntPoint&);
 
     COMPtr<IDataObject> m_dataObject;
     COMPtr<WCDataObject> m_writableDataObject;
+    DragDataMap m_dragDataMap;
     Frame* m_frame;
 };
 
index 906119d..c5b99ea 100644 (file)
@@ -26,6 +26,7 @@
 #include "config.h"
 #include "DragData.h"
 
+#include "COMPtr.h"
 #include "ClipboardUtilitiesWin.h"
 #include "Frame.h"
 #include "DocumentFragment.h"
 #include <objidl.h>
 #include <shlwapi.h>
 #include <wininet.h>
+#include <wtf/Forward.h>
+#include <wtf/Hashmap.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefPtr.h>
 
 namespace WebCore {
 
+DragData::DragData(const DragDataMap& data, const IntPoint& clientPosition, const IntPoint& globalPosition,
+    DragOperation sourceOperationMask, DragApplicationFlags flags)
+    : m_clientPosition(clientPosition)
+    , m_globalPosition(globalPosition)
+    , m_platformDragData(0)
+    , m_draggingSourceOperationMask(sourceOperationMask)
+    , m_applicationFlags(flags)
+    , m_dragDataMap(data)
+{
+}
+
 bool DragData::containsURL(Frame*, FilenameConversionPolicy filenamePolicy) const
 {
-    return SUCCEEDED(m_platformDragData->QueryGetData(urlWFormat())) 
-        || SUCCEEDED(m_platformDragData->QueryGetData(urlFormat()))
-        || (filenamePolicy == ConvertFilenames
-            && (SUCCEEDED(m_platformDragData->QueryGetData(filenameWFormat()))
-                || SUCCEEDED(m_platformDragData->QueryGetData(filenameFormat()))));
+    if (m_platformDragData)
+        return SUCCEEDED(m_platformDragData->QueryGetData(urlWFormat())) 
+            || SUCCEEDED(m_platformDragData->QueryGetData(urlFormat()))
+            || (filenamePolicy == ConvertFilenames
+                && (SUCCEEDED(m_platformDragData->QueryGetData(filenameWFormat()))
+                    || SUCCEEDED(m_platformDragData->QueryGetData(filenameFormat()))));
+    return m_dragDataMap.contains(urlWFormat()->cfFormat) || m_dragDataMap.contains(urlFormat()->cfFormat)
+        || (filenamePolicy == ConvertFilenames && (m_dragDataMap.contains(filenameWFormat()->cfFormat) || m_dragDataMap.contains(filenameFormat()->cfFormat)));
+}
+
+const DragDataMap& DragData::dragDataMap()
+{
+    if (!m_dragDataMap.isEmpty() || !m_platformDragData)
+        return m_dragDataMap;
+    // Enumerate clipboard content and load it in the map.
+    COMPtr<IEnumFORMATETC> itr;
+
+    if (FAILED(m_platformDragData->EnumFormatEtc(DATADIR_GET, &itr)) || !itr)
+        return m_dragDataMap;
+
+    FORMATETC dataFormat;
+    while (itr->Next(1, &dataFormat, 0) == S_OK) {
+        Vector<String> dataStrings;
+        getClipboardData(m_platformDragData, &dataFormat, dataStrings);
+        if (!dataStrings.isEmpty())
+            m_dragDataMap.set(dataFormat.cfFormat, dataStrings); 
+    }
+    return m_dragDataMap;
 }
 
 String DragData::asURL(Frame*, FilenameConversionPolicy filenamePolicy, String* title) const
 {
     bool success;
-    return getURL(m_platformDragData, filenamePolicy, success, title);
+    return (m_platformDragData) ? getURL(m_platformDragData, filenamePolicy, success, title) : getURL(&m_dragDataMap, filenamePolicy, title);
 }
 
 bool DragData::containsFiles() const
 {
-    return SUCCEEDED(m_platformDragData->QueryGetData(cfHDropFormat()));
+    return (m_platformDragData) ? SUCCEEDED(m_platformDragData->QueryGetData(cfHDropFormat())) : m_dragDataMap.contains(cfHDropFormat()->cfFormat);
 }
 
 void DragData::asFilenames(Vector<String>& result) const
 {
-    WCHAR filename[MAX_PATH];
-    
-    STGMEDIUM medium;
-    if (FAILED(m_platformDragData->GetData(cfHDropFormat(), &medium)))
-        return;
-    
-    HDROP hdrop = (HDROP)GlobalLock(medium.hGlobal);
-    
-    if (!hdrop)
-        return;
+    if (m_platformDragData) {
+        WCHAR filename[MAX_PATH];
+        
+        STGMEDIUM medium;
+        if (FAILED(m_platformDragData->GetData(cfHDropFormat(), &medium)))
+            return;
+        
+        HDROP hdrop = (HDROP)GlobalLock(medium.hGlobal);
+        
+        if (!hdrop)
+            return;
 
-    const unsigned numFiles = DragQueryFileW(hdrop, 0xFFFFFFFF, 0, 0);
-    for (unsigned i = 0; i < numFiles; i++) {
-        if (!DragQueryFileW(hdrop, 0, filename, WTF_ARRAY_LENGTH(filename)))
-            continue;
-        result.append((UChar*)filename);
-    }
+        const unsigned numFiles = DragQueryFileW(hdrop, 0xFFFFFFFF, 0, 0);
+        for (unsigned i = 0; i < numFiles; i++) {
+            if (!DragQueryFileW(hdrop, 0, filename, WTF_ARRAY_LENGTH(filename)))
+                continue;
+            result.append((UChar*)filename);
+        }
 
-    // Free up memory from drag
-    DragFinish(hdrop);
+        // Free up memory from drag
+        DragFinish(hdrop);
 
-    GlobalUnlock(medium.hGlobal);
+        GlobalUnlock(medium.hGlobal);
+        return;
+    }
+    result = m_dragDataMap.get(cfHDropFormat()->cfFormat);
 }
 
 bool DragData::containsPlainText() const
 {
-    return SUCCEEDED(m_platformDragData->QueryGetData(plainTextWFormat()))
-        || SUCCEEDED(m_platformDragData->QueryGetData(plainTextFormat()));
+    if (m_platformDragData)
+        return SUCCEEDED(m_platformDragData->QueryGetData(plainTextWFormat()))
+            || SUCCEEDED(m_platformDragData->QueryGetData(plainTextFormat()));
+    return m_dragDataMap.contains(plainTextWFormat()->cfFormat) || m_dragDataMap.contains(plainTextFormat()->cfFormat);
 }
 
 String DragData::asPlainText(Frame*) const
 {
     bool success;
-    return getPlainText(m_platformDragData, success);
+    return (m_platformDragData) ? getPlainText(m_platformDragData, success) : getPlainText(&m_dragDataMap);
 }
 
 bool DragData::containsColor() const
@@ -103,14 +148,16 @@ bool DragData::containsColor() const
 
 bool DragData::canSmartReplace() const
 {
-    return SUCCEEDED(m_platformDragData->QueryGetData(smartPasteFormat())); 
+    if (m_platformDragData)
+        return SUCCEEDED(m_platformDragData->QueryGetData(smartPasteFormat()));
+    return m_dragDataMap.contains(smartPasteFormat()->cfFormat);
 }
 
 bool DragData::containsCompatibleContent() const
 {
     return containsPlainText() || containsURL(0) 
-        || containsHTML(m_platformDragData) 
-        || containsFilenames(m_platformDragData) 
+        || ((m_platformDragData) ? (containsHTML(m_platformDragData) || containsFilenames(m_platformDragData))
+            : (containsHTML(&m_dragDataMap) || containsFilenames(&m_dragDataMap)))
         || containsColor();
 }
 
@@ -125,16 +172,29 @@ PassRefPtr<DocumentFragment> DragData::asFragment(Frame* frame, PassRefPtr<Range
      * * TIFF
      * * PICT
      */
-        
-     if (containsFilenames(m_platformDragData))
-         if (PassRefPtr<DocumentFragment> fragment = fragmentFromFilenames(frame->document(), m_platformDragData))
-             return fragment;
-
-     if (containsHTML(m_platformDragData))
-         if (PassRefPtr<DocumentFragment> fragment = fragmentFromHTML(frame->document(), m_platformDragData))
-             return fragment;
-
-     return 0;
+     
+    if (m_platformDragData) {
+        if (containsFilenames(m_platformDragData)) {
+            if (PassRefPtr<DocumentFragment> fragment = fragmentFromFilenames(frame->document(), m_platformDragData))
+                return fragment;
+        }
+
+        if (containsHTML(m_platformDragData)) {
+            if (PassRefPtr<DocumentFragment> fragment = fragmentFromHTML(frame->document(), m_platformDragData))
+                return fragment;
+        }
+    } else {
+        if (containsFilenames(&m_dragDataMap)) {
+            if (PassRefPtr<DocumentFragment> fragment = fragmentFromFilenames(frame->document(), &m_dragDataMap))
+                return fragment;
+        }
+
+        if (containsHTML(&m_dragDataMap)) {
+            if (PassRefPtr<DocumentFragment> fragment = fragmentFromHTML(frame->document(), &m_dragDataMap))
+                return fragment;
+        }
+    }
+    return 0;
 }
 
 Color DragData::asColor() const
@@ -143,4 +203,3 @@ Color DragData::asColor() const
 }
 
 }
-
index 62b2dd4..5ff519f 100644 (file)
@@ -1,3 +1,47 @@
+2011-01-26  Enrica Casucci  <enrica@apple.com>
+
+        Reviewed by Darin Adler and Adam Roben.
+
+        WebKit2: add support for drag and drop on Windows
+        https://bugs.webkit.org/show_bug.cgi?id=52775
+        <rdar://problem/8514409>
+
+        On Windows the access to the content being dragged is
+        provided via the IDataObject interface that is made available
+        to the window that registers itself as drop target.
+        Since this interface cannot be accessed from the WebProcess,
+        in every call to one of the methods of the IDropTarget interface
+        we serialize the content of the drag clipboard and send it over to
+        the WebProcess. The implementation uses the same messages as the
+        Mac one, with slightly different parameters to pass the serialized
+        clipboard.
+
+        * UIProcess/WebPageProxy.cpp:
+        (WebKit::WebPageProxy::performDragControllerAction): Added Windows
+        specific implementation.
+        * UIProcess/WebPageProxy.h:
+        * UIProcess/win/WebView.cpp:
+        (WebKit::WebView::WebView): Added dropTargetHelper object creation.
+        (WebKit::WebView::initialize): Added to register for drag/drop with out
+        refcount issues.
+        (WebKit::WebView::close):
+        (WebKit::WebView::windowReceivedMessage):
+        (WebKit::WebView::QueryInterface):
+        (WebKit::WebView::AddRef):
+        (WebKit::WebView::Release):
+        (WebKit::dragOperationToDragCursor):
+        (WebKit::WebView::keyStateToDragOperation):
+        (WebKit::WebView::DragEnter):
+        (WebKit::WebView::DragOver):
+        (WebKit::WebView::DragLeave):
+        (WebKit::WebView::Drop):
+        * UIProcess/win/WebView.h:
+        (WebKit::WebView::create):
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::WebPage::performDragControllerAction):
+        * WebProcess/WebPage/WebPage.h:
+        * WebProcess/WebPage/WebPage.messages.in:
+
 2011-01-26  Alexey Proskuryakov  <ap@apple.com>
 
         Reviewed by Darin Adler.
index f24905d..5215953 100644 (file)
@@ -612,7 +612,13 @@ void WebPageProxy::performDragControllerAction(DragControllerAction action, WebC
 {
     if (!isValid())
         return;
+#if PLATFORM(WIN)
+    // FIXME: We should pass the drag data map only on DragEnter.
+    process()->send(Messages::WebPage::PerformDragControllerAction(action, dragData->clientPosition(), dragData->globalPosition(),
+        dragData->draggingSourceOperationMask(), dragData->dragDataMap(), dragData->flags()), m_pageID);
+#else
     process()->send(Messages::WebPage::PerformDragControllerAction(action, dragData->clientPosition(), dragData->globalPosition(), dragData->draggingSourceOperationMask(), dragStorageName, dragData->flags()), m_pageID);
+#endif
 }
 
 void WebPageProxy::didPerformDragControllerAction(uint64_t resultOperation)
index 7caf9d9..d0613ac 100644 (file)
@@ -294,7 +294,7 @@ public:
     void backForwardRemovedItem(uint64_t itemID);
 
     // Drag and drop support.
-    void performDragControllerAction(DragControllerAction, WebCore::DragData*, const String&);
+    void performDragControllerAction(DragControllerAction, WebCore::DragData*, const String& = String());
     void didPerformDragControllerAction(uint64_t resultOperation);
     void dragEnded(const WebCore::IntPoint& clientPosition, const WebCore::IntPoint& globalPosition, uint64_t operation);
 #if PLATFORM(MAC)
index e94c8e4..b47ce23 100644 (file)
@@ -243,6 +243,8 @@ WebView::WebView(RECT rect, WebContext* context, WebPageGroup* pageGroup, HWND p
 
     m_page->initializeWebPage();
 
+    CoCreateInstance(CLSID_DragDropHelper, 0, CLSCTX_INPROC_SERVER, IID_IDropTargetHelper, (void**)&m_dropTargetHelper);
+
     ::ShowWindow(m_window, SW_SHOW);
 
     // FIXME: Initializing the tooltip window here matches WebKit win, but seems like something
@@ -260,6 +262,11 @@ WebView::~WebView()
         ::DestroyWindow(m_toolTipWindow);
 }
 
+void WebView::initialize()
+{
+    ::RegisterDragDrop(m_window, this);
+}
+
 void WebView::setParentWindow(HWND parentWindow)
 {
     if (m_window) {
@@ -569,6 +576,7 @@ void WebView::stopTrackingMouseLeave()
 
 void WebView::close()
 {
+    ::RevokeDragDrop(m_window);
     setParentWindow(0);
     m_page->close();
 }
@@ -1092,4 +1100,131 @@ void WebView::windowReceivedMessage(HWND, UINT message, WPARAM wParam, LPARAM)
     }
 }
 
+HRESULT STDMETHODCALLTYPE WebView::QueryInterface(REFIID riid, void** ppvObject)
+{
+    *ppvObject = 0;
+    if (IsEqualGUID(riid, IID_IUnknown))
+        *ppvObject = static_cast<IUnknown*>(this);
+    else if (IsEqualGUID(riid, IID_IDropTarget))
+        *ppvObject = static_cast<IDropTarget*>(this);
+    else
+        return E_NOINTERFACE;
+
+    AddRef();
+    return S_OK;
+}
+
+ULONG STDMETHODCALLTYPE WebView::AddRef(void)
+{
+    ref();
+    return refCount();
+}
+
+ULONG STDMETHODCALLTYPE WebView::Release(void)
+{
+    deref();
+    return refCount();
+}
+
+static DWORD dragOperationToDragCursor(DragOperation op)
+{
+    DWORD res = DROPEFFECT_NONE;
+    if (op & DragOperationCopy) 
+        res = DROPEFFECT_COPY;
+    else if (op & DragOperationLink) 
+        res = DROPEFFECT_LINK;
+    else if (op & DragOperationMove) 
+        res = DROPEFFECT_MOVE;
+    else if (op & DragOperationGeneric) 
+        res = DROPEFFECT_MOVE; // This appears to be the Firefox behaviour
+    return res;
+}
+
+WebCore::DragOperation WebView::keyStateToDragOperation(DWORD grfKeyState) const
+{
+    if (!m_page)
+        return DragOperationNone;
+
+    // Conforms to Microsoft's key combinations as documented for 
+    // IDropTarget::DragOver. Note, grfKeyState is the current 
+    // state of the keyboard modifier keys on the keyboard. See:
+    // <http://msdn.microsoft.com/en-us/library/ms680129(VS.85).aspx>.
+    DragOperation operation = m_page->dragOperation();
+
+    if ((grfKeyState & (MK_CONTROL | MK_SHIFT)) == (MK_CONTROL | MK_SHIFT))
+        operation = DragOperationLink;
+    else if ((grfKeyState & MK_CONTROL) == MK_CONTROL)
+        operation = DragOperationCopy;
+    else if ((grfKeyState & MK_SHIFT) == MK_SHIFT)
+        operation = DragOperationGeneric;
+
+    return operation;
+}
+
+HRESULT STDMETHODCALLTYPE WebView::DragEnter(IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect)
+{
+    m_dragData = 0;
+    m_page->resetDragOperation();
+
+    if (m_dropTargetHelper)
+        m_dropTargetHelper->DragEnter(m_window, pDataObject, (POINT*)&pt, *pdwEffect);
+
+    POINTL localpt = pt;
+    ::ScreenToClient(m_window, (LPPOINT)&localpt);
+    DragData data(pDataObject, IntPoint(localpt.x, localpt.y), IntPoint(pt.x, pt.y), keyStateToDragOperation(grfKeyState));
+    m_page->performDragControllerAction(DragControllerActionEntered, &data);
+    *pdwEffect = dragOperationToDragCursor(m_page->dragOperation());
+
+    m_lastDropEffect = *pdwEffect;
+    m_dragData = pDataObject;
+
+    return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE WebView::DragOver(DWORD grfKeyState, POINTL pt, DWORD* pdwEffect)
+{
+    if (m_dropTargetHelper)
+        m_dropTargetHelper->DragOver((POINT*)&pt, *pdwEffect);
+
+    if (m_dragData) {
+        POINTL localpt = pt;
+        ::ScreenToClient(m_window, (LPPOINT)&localpt);
+        DragData data(m_dragData.get(), IntPoint(localpt.x, localpt.y), IntPoint(pt.x, pt.y), keyStateToDragOperation(grfKeyState));
+        m_page->performDragControllerAction(DragControllerActionUpdated, &data);
+        *pdwEffect = dragOperationToDragCursor(m_page->dragOperation());
+    } else
+        *pdwEffect = DROPEFFECT_NONE;
+
+    m_lastDropEffect = *pdwEffect;
+    return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE WebView::DragLeave()
+{
+    if (m_dropTargetHelper)
+        m_dropTargetHelper->DragLeave();
+
+    if (m_dragData) {
+        DragData data(m_dragData.get(), IntPoint(), IntPoint(), DragOperationNone);
+        m_page->performDragControllerAction(DragControllerActionExited, &data);
+        m_dragData = 0;
+        m_page->resetDragOperation();
+    }
+    return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE WebView::Drop(IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect)
+{
+    if (m_dropTargetHelper)
+        m_dropTargetHelper->Drop(pDataObject, (POINT*)&pt, *pdwEffect);
+
+    m_dragData = 0;
+    *pdwEffect = m_lastDropEffect;
+    POINTL localpt = pt;
+    ::ScreenToClient(m_window, (LPPOINT)&localpt);
+    DragData data(pDataObject, IntPoint(localpt.x, localpt.y), IntPoint(pt.x, pt.y), keyStateToDragOperation(grfKeyState));
+    m_page->performDragControllerAction(DragControllerActionPerformDrag, &data);
+    return S_OK;
+}
+
 } // namespace WebKit
index 31f6c45..c04a0c6 100644 (file)
 #include "APIObject.h"
 #include "PageClient.h"
 #include "WebPageProxy.h"
+#include <WebCore/COMPtr.h>
+#include <WebCore/DragActions.h>
+#include <WebCore/DragData.h>
 #include <WebCore/WindowMessageListener.h>
 #include <wtf/Forward.h>
 #include <wtf/PassRefPtr.h>
 #include <wtf/RefPtr.h>
+#include <ShlObj.h>
+
+interface IDropTargetHelper;
 
 namespace WebKit {
 
 class DrawingAreaProxy;
 
-class WebView : public APIObject, public PageClient, WebCore::WindowMessageListener {
+class WebView : public APIObject, public PageClient, WebCore::WindowMessageListener, public IDropTarget {
 public:
     static PassRefPtr<WebView> create(RECT rect, WebContext* context, WebPageGroup* pageGroup, HWND parentWindow)
     {
-        return adoptRef(new WebView(rect, context, pageGroup, parentWindow));
+        RefPtr<WebView> webView = adoptRef(new WebView(rect, context, pageGroup, parentWindow));
+        webView->initialize();
+        return webView;
     }
     ~WebView();
 
@@ -52,6 +60,18 @@ public:
     void setIsInWindow(bool);
     void setOverrideCursor(HCURSOR overrideCursor);
     void setInitialFocus(bool forward);
+    void initialize();
+
+    // IUnknown
+    virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject);
+    virtual ULONG STDMETHODCALLTYPE AddRef(void);
+    virtual ULONG STDMETHODCALLTYPE Release(void);
+
+    // IDropTarget
+    virtual HRESULT STDMETHODCALLTYPE DragEnter(IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect);
+    virtual HRESULT STDMETHODCALLTYPE DragOver(DWORD grfKeyState, POINTL pt, DWORD* pdwEffect);
+    virtual HRESULT STDMETHODCALLTYPE DragLeave();
+    virtual HRESULT STDMETHODCALLTYPE Drop(IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect);
 
     WebPageProxy* page() const { return m_page.get(); }
 
@@ -142,6 +162,7 @@ private:
     void didFinishLoadingDataForCustomRepresentation(const CoreIPC::DataReference&);
     virtual double customRepresentationZoomFactor();
     virtual void setCustomRepresentationZoomFactor(double);
+    WebCore::DragOperation keyStateToDragOperation(DWORD grfKeyState) const;
 
     virtual HWND nativeWindow();
 
@@ -165,6 +186,13 @@ private:
     RefPtr<WebPageProxy> m_page;
 
     unsigned m_inIMEComposition;
+    COMPtr<IDataObject> m_dragData;
+    COMPtr<IDropTargetHelper> m_dropTargetHelper;
+    // FIXME: This variable is part of a workaround. The drop effect (pdwEffect) passed to Drop is incorrect. 
+    // We set this variable in DragEnter and DragOver so that it can be used in Drop to set the correct drop effect. 
+    // Thus, on return from DoDragDrop we have the correct pdwEffect for the drag-and-drop operation.
+    // (see https://bugs.webkit.org/show_bug.cgi?id=29264)
+    DWORD m_lastDropEffect;
 };
 
 } // namespace WebKit
index b4df4df..dd61860 100644 (file)
@@ -1331,6 +1331,37 @@ bool WebPage::handleEditingKeyboardEvent(KeyboardEvent* evt)
 }
 #endif
 
+#if PLATFORM(WIN)
+void WebPage::performDragControllerAction(uint64_t action, WebCore::IntPoint clientPosition, WebCore::IntPoint globalPosition, uint64_t draggingSourceOperationMask, const WebCore::DragDataMap& dataMap, uint32_t flags)
+{
+    if (!m_page) {
+        send(Messages::WebPageProxy::DidPerformDragControllerAction(DragOperationNone));
+        return;
+    }
+
+    DragData dragData(dataMap, clientPosition, globalPosition, static_cast<DragOperation>(draggingSourceOperationMask), static_cast<DragApplicationFlags>(flags));
+    switch (action) {
+    case DragControllerActionEntered:
+        send(Messages::WebPageProxy::DidPerformDragControllerAction(m_page->dragController()->dragEntered(&dragData)));
+        break;
+
+    case DragControllerActionUpdated:
+        send(Messages::WebPageProxy::DidPerformDragControllerAction(m_page->dragController()->dragUpdated(&dragData)));
+        break;
+        
+    case DragControllerActionExited:
+        m_page->dragController()->dragExited(&dragData);
+        break;
+        
+    case DragControllerActionPerformDrag:
+        m_page->dragController()->performDrag(&dragData);
+        break;
+        
+    default:
+        ASSERT_NOT_REACHED();
+    }
+}
+#else
 void WebPage::performDragControllerAction(uint64_t action, WebCore::IntPoint clientPosition, WebCore::IntPoint globalPosition, uint64_t draggingSourceOperationMask, const String& dragStorageName, uint32_t flags)
 {
     if (!m_page) {
@@ -1360,6 +1391,7 @@ void WebPage::performDragControllerAction(uint64_t action, WebCore::IntPoint cli
         ASSERT_NOT_REACHED();
     }
 }
+#endif
 
 void WebPage::dragEnded(WebCore::IntPoint clientPosition, WebCore::IntPoint globalPosition, uint64_t operation)
 {
index 3dae655..1fefb5b 100644 (file)
@@ -40,6 +40,7 @@
 #include "Plugin.h"
 #include "SandboxExtension.h"
 #include "WebEditCommand.h"
+#include <WebCore/DragData.h>
 #include <WebCore/Editor.h>
 #include <WebCore/FrameLoaderTypes.h>
 #include <WebCore/IntRect.h>
@@ -304,7 +305,11 @@ public:
 #endif
 
     void replaceSelectionWithText(WebCore::Frame*, const String&);
+#if PLATFORM(WIN)
+    void performDragControllerAction(uint64_t action, WebCore::IntPoint clientPosition, WebCore::IntPoint globalPosition, uint64_t draggingSourceOperationMask, const WebCore::DragDataMap&, uint32_t flags);
+#else
     void performDragControllerAction(uint64_t action, WebCore::IntPoint clientPosition, WebCore::IntPoint globalPosition, uint64_t draggingSourceOperationMask, const WTF::String& dragStorageName, uint32_t flags);
+#endif
     void dragEnded(WebCore::IntPoint clientPosition, WebCore::IntPoint globalPosition, uint64_t operation);
 
     void beginPrinting(uint64_t frameID, const PrintInfo&);
index afd4c72..6ce4c31 100644 (file)
@@ -106,7 +106,12 @@ messages -> WebPage {
     CountStringMatches(WTF::String string, uint32_t findOptions, unsigned maxMatchCount)
 
     # Drag and drop.
+#if PLATFORM(WIN)
+    PerformDragControllerAction(uint64_t action, WebCore::IntPoint clientPosition, WebCore::IntPoint globalPosition, uint64_t draggingSourceOperationMask, HashMap<UINT,Vector<String>> dataMap, uint32_t flags)
+#endif
+#if !PLATFORM(WIN)
     PerformDragControllerAction(uint64_t action, WebCore::IntPoint clientPosition, WebCore::IntPoint globalPosition, uint64_t draggingSourceOperationMask, WTF::String dragStorageName, uint32_t flags)
+#endif
     DragEnded(WebCore::IntPoint clientPosition, WebCore::IntPoint globalPosition, uint64_t operation)
 
     # Popup menu.