Changeset 261911 in webkit


Ignore:
Timestamp:
May 20, 2020 5:39:22 AM (4 years ago)
Author:
Carlos Garcia Campos
Message:

[GTK4] Add support for drag and drop operations
https://bugs.webkit.org/show_bug.cgi?id=211779

Reviewed by Adrian Perez de Castro.

Source/WebCore:

Move the code to create a GdkTexture from an Image from CursorGtk to ImageGtk and add Image::gdkTexture().

  • platform/graphics/BitmapImage.h:
  • platform/graphics/Image.h:

(WebCore::Image::gdkTexture):

  • platform/graphics/gtk/ImageGtk.cpp:

(WebCore::BitmapImage::gdkTexture):

  • platform/gtk/CursorGtk.cpp:

(WebCore::createCustomCursor):

Source/WebKit:

  • UIProcess/API/gtk/DragSource.h:
  • UIProcess/API/gtk/DragSourceGtk4.cpp:

(WebKit::DragSource::begin):

  • UIProcess/API/gtk/DropTarget.h:
  • UIProcess/API/gtk/DropTargetGtk4.cpp:

(WebKit::DropTarget::DropTarget):
(WebKit::DropTarget::~DropTarget):
(WebKit::DropTarget::accept):
(WebKit::DropReadAsyncData::DropReadAsyncData):
(WebKit::DropTarget::loadData):
(WebKit::DropTarget::didLoadData):
(WebKit::DropTarget::enter):
(WebKit::DropTarget::update):
(WebKit::DropTarget::didPerformAction):
(WebKit::DropTarget::leave):
(WebKit::DropTarget::drop):

Location:
trunk/Source
Files:
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r261910 r261911  
     12020-05-12  Carlos Garcia Campos  <cgarcia@igalia.com>
     2
     3        [GTK4] Add support for drag and drop operations
     4        https://bugs.webkit.org/show_bug.cgi?id=211779
     5
     6        Reviewed by Adrian Perez de Castro.
     7
     8        Move the code to create a GdkTexture from an Image from CursorGtk to ImageGtk and add Image::gdkTexture().
     9
     10        * platform/graphics/BitmapImage.h:
     11        * platform/graphics/Image.h:
     12        (WebCore::Image::gdkTexture):
     13        * platform/graphics/gtk/ImageGtk.cpp:
     14        (WebCore::BitmapImage::gdkTexture):
     15        * platform/gtk/CursorGtk.cpp:
     16        (WebCore::createCustomCursor):
     17
    1182020-05-20  Sam Weinig  <weinig@apple.com>
    219
  • trunk/Source/WebCore/platform/graphics/BitmapImage.h

    r260415 r261911  
    131131#if PLATFORM(GTK)
    132132    GdkPixbuf* getGdkPixbuf() override;
     133#if USE(GTK4)
     134    GdkTexture* gdkTexture() override;
     135#endif
    133136#endif
    134137
  • trunk/Source/WebCore/platform/graphics/Image.h

    r254841 r261911  
    5959#if PLATFORM(GTK)
    6060typedef struct _GdkPixbuf GdkPixbuf;
     61#if USE(GTK4)
     62typedef struct _GdkTexture GdkTexture;
     63#endif
    6164#endif
    6265
     
    171174#if PLATFORM(GTK)
    172175    virtual GdkPixbuf* getGdkPixbuf() { return nullptr; }
     176#if USE(GTK4)
     177    virtual GdkTexture* gdkTexture() { return nullptr; }
     178#endif
    173179#endif
    174180
  • trunk/Source/WebCore/platform/graphics/gtk/ImageGtk.cpp

    r260425 r261911  
    3030#include "SharedBuffer.h"
    3131#include <cairo.h>
     32#include <gdk/gdk.h>
    3233#include <wtf/glib/GRefPtr.h>
    3334#include <wtf/glib/GUniquePtr.h>
     
    6061}
    6162
     63#if USE(GTK4)
     64GdkTexture* BitmapImage::gdkTexture()
     65{
     66    RefPtr<cairo_surface_t> surface = nativeImageForCurrentFrame();
     67    if (!surface)
     68        return nullptr;
     69
     70    ASSERT(cairo_image_surface_get_format(surface.get()) == CAIRO_FORMAT_ARGB32);
     71    auto width = cairo_image_surface_get_width(surface.get());
     72    auto height = cairo_image_surface_get_height(surface.get());
     73    auto stride = cairo_image_surface_get_stride(surface.get());
     74    auto* data = cairo_image_surface_get_data(surface.get());
     75    GRefPtr<GBytes> bytes = adoptGRef(g_bytes_new_with_free_func(data, height * stride, [](gpointer data) {
     76        cairo_surface_destroy(static_cast<cairo_surface_t*>(data));
     77    }, surface.leakRef()));
     78    return gdk_memory_texture_new(width, height, GDK_MEMORY_DEFAULT, bytes.get(), stride);
    6279}
     80#endif
     81
     82}
  • trunk/Source/WebCore/platform/gtk/CursorGtk.cpp

    r260752 r261911  
    5656static GRefPtr<GdkCursor> createCustomCursor(Image* image, const IntPoint& hotSpot)
    5757{
     58#if USE(GTK4)
     59    auto texture = adoptGRef(image->gdkTexture());
     60    if (!texture)
     61        return nullptr;
     62
     63    IntPoint effectiveHotSpot = determineHotSpot(image, hotSpot);
     64    return adoptGRef(gdk_cursor_new_from_texture(texture.get(), effectiveHotSpot.x(), effectiveHotSpot.y(), fallbackCursor().get()));
     65#else
    5866    RefPtr<cairo_surface_t> surface = image->nativeImageForCurrentFrame();
    5967    if (!surface)
     
    6169
    6270    IntPoint effectiveHotSpot = determineHotSpot(image, hotSpot);
    63 
    64 #if USE(GTK4)
    65     ASSERT(cairo_image_surface_get_format(surface.get()) == CAIRO_FORMAT_ARGB32);
    66     auto width = cairo_image_surface_get_width(surface.get());
    67     auto height = cairo_image_surface_get_height(surface.get());
    68     auto stride = cairo_image_surface_get_stride(surface.get());
    69     GRefPtr<GBytes> bytes = adoptGRef(g_bytes_new_with_free_func(cairo_image_surface_get_data(surface.get()), height * stride,
    70         [](gpointer data) {
    71             cairo_surface_destroy(static_cast<cairo_surface_t*>(data));
    72         }, surface.leakRef()));
    73     auto texture = adoptGRef(gdk_memory_texture_new(width, height, GDK_MEMORY_A8R8G8B8_PREMULTIPLIED, bytes.get(), stride));
    74     return adoptGRef(gdk_cursor_new_from_texture(texture.get(), effectiveHotSpot.x(), effectiveHotSpot.y(), fallbackCursor().get()));
    75 #else
    7671    return adoptGRef(gdk_cursor_new_from_surface(gdk_display_get_default(), surface.get(), effectiveHotSpot.x(), effectiveHotSpot.y()));
    7772#endif // USE(GTK4)
  • trunk/Source/WebKit/ChangeLog

    r261906 r261911  
     12020-05-12  Carlos Garcia Campos  <cgarcia@igalia.com>
     2
     3        [GTK4] Add support for drag and drop operations
     4        https://bugs.webkit.org/show_bug.cgi?id=211779
     5
     6        Reviewed by Adrian Perez de Castro.
     7
     8        * UIProcess/API/gtk/DragSource.h:
     9        * UIProcess/API/gtk/DragSourceGtk4.cpp:
     10        (WebKit::DragSource::begin):
     11        * UIProcess/API/gtk/DropTarget.h:
     12        * UIProcess/API/gtk/DropTargetGtk4.cpp:
     13        (WebKit::DropTarget::DropTarget):
     14        (WebKit::DropTarget::~DropTarget):
     15        (WebKit::DropTarget::accept):
     16        (WebKit::DropReadAsyncData::DropReadAsyncData):
     17        (WebKit::DropTarget::loadData):
     18        (WebKit::DropTarget::didLoadData):
     19        (WebKit::DropTarget::enter):
     20        (WebKit::DropTarget::update):
     21        (WebKit::DropTarget::didPerformAction):
     22        (WebKit::DropTarget::leave):
     23        (WebKit::DropTarget::drop):
     24
    1252020-05-19  Wenson Hsieh  <wenson_hsieh@apple.com>
    226
  • trunk/Source/WebKit/UIProcess/API/gtk/DragSource.h

    r261802 r261911  
    3636typedef struct _GtkWidget GtkWidget;
    3737
    38 #if !USE(GTK4)
     38#if USE(GTK4)
     39typedef struct _GdkDrag GdkDrag;
     40#else
    3941typedef struct _GdkDragContext GdkDragContext;
    4042#endif
     
    5557private:
    5658    GtkWidget* m_webView { nullptr };
    57 #if !USE(GTK4)
     59#if USE(GTK4)
     60    GRefPtr<GdkDrag> m_drag;
     61#else
    5862    GRefPtr<GdkDragContext> m_drag;
    5963#endif
  • trunk/Source/WebKit/UIProcess/API/gtk/DragSourceGtk4.cpp

    r261802 r261911  
    4545}
    4646
    47 void DragSource::begin(SelectionData&&, DragOperation, RefPtr<ShareableBitmap>&&)
     47void DragSource::begin(SelectionData&& selectionData, DragOperation operation, RefPtr<ShareableBitmap>&& image)
    4848{
     49    if (m_drag) {
     50        gdk_drag_drop_done(m_drag.get(), FALSE);
     51        m_drag = nullptr;
     52    }
     53
     54    m_selectionData = WTFMove(selectionData);
     55
     56    Vector<GdkContentProvider*> providers;
     57    if (m_selectionData->hasMarkup()) {
     58        CString markup = m_selectionData->markup().utf8();
     59        GRefPtr<GBytes> bytes = adoptGRef(g_bytes_new(markup.data(), markup.length()));
     60        providers.append(gdk_content_provider_new_for_bytes("text/html", bytes.get()));
     61    }
     62
     63    if (m_selectionData->hasURIList()) {
     64        CString uriList = m_selectionData->uriList().utf8();
     65        GRefPtr<GBytes> bytes = adoptGRef(g_bytes_new(uriList.data(), uriList.length()));
     66        providers.append(gdk_content_provider_new_for_bytes("text/uri-list", bytes.get()));
     67    }
     68
     69    if (m_selectionData->hasURL()) {
     70        CString urlString = m_selectionData->url().string().utf8();
     71        gchar* url = g_strdup_printf("%s\n%s", urlString.data(), m_selectionData->hasText() ? m_selectionData->text().utf8().data() : urlString.data());
     72        GRefPtr<GBytes> bytes = adoptGRef(g_bytes_new_take(url, strlen(url)));
     73        providers.append(gdk_content_provider_new_for_bytes("_NETSCAPE_URL", bytes.get()));
     74    }
     75
     76    if (m_selectionData->hasImage()) {
     77        GRefPtr<GdkPixbuf> pixbuf = adoptGRef(m_selectionData->image()->getGdkPixbuf());
     78        providers.append(gdk_content_provider_new_typed(GDK_TYPE_PIXBUF, pixbuf.get()));
     79    }
     80
     81    if (m_selectionData->hasText())
     82        providers.append(gdk_content_provider_new_typed(G_TYPE_STRING, m_selectionData->text().utf8().data()));
     83
     84    if (m_selectionData->canSmartReplace()) {
     85        GRefPtr<GBytes> bytes = adoptGRef(g_bytes_new(nullptr, 0));
     86        providers.append(gdk_content_provider_new_for_bytes("application/vnd.webkitgtk.smartpaste", bytes.get()));
     87    }
     88
     89    auto* surface = gtk_native_get_surface(gtk_widget_get_native(m_webView));
     90    auto* device = gdk_seat_get_pointer(gdk_display_get_default_seat(gtk_widget_get_display(m_webView)));
     91    GRefPtr<GdkContentProvider> provider = adoptGRef(gdk_content_provider_new_union(providers.data(), providers.size()));
     92    m_drag = adoptGRef(gdk_drag_begin(surface, device, provider.get(), dragOperationToGdkDragActions(operation), 0, 0));
     93    g_signal_connect(m_drag.get(), "dnd-finished", G_CALLBACK(+[](GdkDrag* gtkDrag, gpointer userData) {
     94        auto& drag = *static_cast<DragSource*>(userData);
     95        if (drag.m_drag.get() != gtkDrag)
     96            return;
     97
     98        drag.m_selectionData = WTF::nullopt;
     99        drag.m_drag = nullptr;
     100
     101        GdkDevice* device = gdk_drag_get_device(gtkDrag);
     102        double x = 0;
     103        double y = 0;
     104        gdk_device_get_surface_at_position(device, &x, &y);
     105
     106        auto* page = webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(drag.m_webView));
     107        ASSERT(page);
     108
     109        IntPoint point(x, y);
     110        page->dragEnded(point, point, gdkDragActionToDragOperation(gdk_drag_get_selected_action(gtkDrag)));
     111    }), this);
     112
     113    g_signal_connect(m_drag.get(), "cancel", G_CALLBACK(+[](GdkDrag* gtkDrag, GdkDragCancelReason, gpointer userData) {
     114        auto& drag = *static_cast<DragSource*>(userData);
     115        if (drag.m_drag.get() != gtkDrag)
     116            return;
     117
     118        drag.m_selectionData = WTF::nullopt;
     119        drag.m_drag = nullptr;
     120    }), this);
     121
     122    auto* dragIcon = gtk_drag_icon_get_for_drag(m_drag.get());
     123    RefPtr<Image> iconImage = image ? image->createImage() : nullptr;
     124    if (iconImage) {
     125        if (GRefPtr<GdkTexture> texture = adoptGRef(iconImage->gdkTexture())) {
     126            gdk_drag_set_hotspot(m_drag.get(), -gdk_texture_get_width(texture.get()) / 2, -gdk_texture_get_height(texture.get()) / 2);
     127            auto* picture = gtk_picture_new_for_paintable(GDK_PAINTABLE(texture.get()));
     128            gtk_drag_icon_set_child(GTK_DRAG_ICON(dragIcon), picture);
     129            return;
     130        }
     131    }
     132
     133    gdk_drag_set_hotspot(m_drag.get(), -2, -2);
     134    auto* child = gtk_image_new_from_icon_name("text-x-generic");
     135    gtk_image_set_icon_size(GTK_IMAGE(child), GTK_ICON_SIZE_LARGE);
     136    gtk_drag_icon_set_child(GTK_DRAG_ICON(dragIcon), child);
    49137}
    50138
  • trunk/Source/WebKit/UIProcess/API/gtk/DropTarget.h

    r261802 r261911  
    3838typedef struct _GtkWidget GtkWidget;
    3939
    40 #if !USE(GTK4)
     40#if USE(GTK4)
     41typedef struct _GdkDrop GdkDrop;
     42#else
    4143typedef struct _GdkDragContext GdkDragContext;
    4244typedef struct _GtkSelectionData GtkSelectionData;
     
    6264    void drop(WebCore::IntPoint&&, unsigned = 0);
    6365
    64 #if !USE(GTK4)
     66#if USE(GTK4)
     67    void loadData(const char* mimeType, CompletionHandler<void(GRefPtr<GBytes>&&)>&&);
     68    void didLoadData();
     69#else
    6570    void dataReceived(WebCore::IntPoint&&, GtkSelectionData*, unsigned, unsigned);
    6671    void leaveTimerFired();
     
    6873
    6974    GtkWidget* m_webView { nullptr };
    70 #if !USE(GTK4)
     75#if USE(GTK4)
     76    GRefPtr<GdkDrop> m_drop;
     77#else
    7178    GRefPtr<GdkDragContext> m_drop;
    7279#endif
     
    7582    Optional<WebCore::SelectionData> m_selectionData;
    7683    WebCore::DragOperation m_operation { WebCore::DragOperationNone };
    77 #if !USE(GTK4)
     84#if USE(GTK4)
     85    GRefPtr<GCancellable> m_cancellable;
     86#else
    7887    RunLoop::Timer<DropTarget> m_leaveTimer;
    7988#endif
  • trunk/Source/WebKit/UIProcess/API/gtk/DropTargetGtk4.cpp

    r261570 r261911  
    3838using namespace WebCore;
    3939
     40enum DropTargetType { Markup, Text, URIList, NetscapeURL, SmartPaste };
     41
    4042DropTarget::DropTarget(GtkWidget* webView)
    4143    : m_webView(webView)
    4244{
     45    auto* formatsBuilder = gdk_content_formats_builder_new();
     46    gdk_content_formats_builder_add_gtype(formatsBuilder, G_TYPE_STRING);
     47    gdk_content_formats_builder_add_mime_type(formatsBuilder, "text/html");
     48    gdk_content_formats_builder_add_mime_type(formatsBuilder, "text/uri-list");
     49    gdk_content_formats_builder_add_mime_type(formatsBuilder, "_NETSCAPE_URL");
     50    gdk_content_formats_builder_add_mime_type(formatsBuilder, "application/vnd.webkitgtk.smartpaste");
     51    auto* target = gtk_drop_target_async_new(gdk_content_formats_builder_free_to_formats(formatsBuilder),
     52        static_cast<GdkDragAction>(GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK));
     53    g_signal_connect(target, "accept", G_CALLBACK(+[](GtkDropTargetAsync*, GdkDrop* gdkDrop, gpointer userData) -> gboolean {
     54        auto& drop = *static_cast<DropTarget*>(userData);
     55        drop.m_drop = gdkDrop;
     56        drop.accept();
     57        return TRUE;
     58    }), this);
     59
     60    g_signal_connect(target, "drag-enter", G_CALLBACK(+[](GtkDropTargetAsync*, GdkDrop* gdkDrop, double x, double y, gpointer userData) -> GdkDragAction {
     61        auto& drop = *static_cast<DropTarget*>(userData);
     62        if (drop.m_drop != gdkDrop)
     63            return static_cast<GdkDragAction>(0);
     64
     65        drop.enter({ clampToInteger(x), clampToInteger(y) });
     66        return dragOperationToSingleGdkDragAction(drop.m_operation);
     67    }), this);
     68
     69    g_signal_connect(target, "drag-motion", G_CALLBACK(+[](GtkDropTargetAsync*, GdkDrop* gdkDrop, double x, double y, gpointer userData) -> GdkDragAction {
     70        auto& drop = *static_cast<DropTarget*>(userData);
     71        if (drop.m_drop != gdkDrop)
     72            return static_cast<GdkDragAction>(0);
     73
     74        drop.update({ clampToInteger(x), clampToInteger(y) });
     75        return dragOperationToSingleGdkDragAction(drop.m_operation);
     76    }), this);
     77
     78    g_signal_connect(target, "drag-leave", G_CALLBACK(+[](GtkDropTargetAsync*, GdkDrop* gdkDrop, gpointer userData) {
     79        auto& drop = *static_cast<DropTarget*>(userData);
     80        if (drop.m_drop != gdkDrop)
     81            return;
     82
     83        drop.leave();
     84    }), this);
     85
     86    g_signal_connect(target, "drop", G_CALLBACK(+[](GtkDropTargetAsync*, GdkDrop* gdkDrop, double x, double y, gpointer userData) -> gboolean {
     87        auto& drop = *static_cast<DropTarget*>(userData);
     88        if (drop.m_drop != gdkDrop)
     89            return FALSE;
     90
     91        drop.drop({ clampToInteger(x), clampToInteger(y) });
     92        return TRUE;
     93    }), this);
     94
     95    gtk_widget_add_controller(m_webView, GTK_EVENT_CONTROLLER(target));
    4396}
    4497
    4598DropTarget::~DropTarget()
    4699{
     100    g_cancellable_cancel(m_cancellable.get());
    47101}
    48102
    49103void DropTarget::accept(unsigned)
    50104{
    51 }
    52 
    53 void DropTarget::loadData(const char*, CompletionHandler<void(GRefPtr<GBytes>&&)>&&)
    54 {
     105    m_position = WTF::nullopt;
     106    m_selectionData = SelectionData();
     107    m_dataRequestCount = 0;
     108    m_cancellable = adoptGRef(g_cancellable_new());
     109
     110    // WebCore needs the selection data to decide, so we need to preload the
     111    // data of targets we support. Once all data requests are done we start
     112    // notifying the web process about the DND events.
     113    auto* formats = gdk_drop_get_formats(m_drop.get());
     114    if (gdk_content_formats_contain_gtype(formats, G_TYPE_STRING)) {
     115        m_dataRequestCount++;
     116        gdk_drop_read_value_async(m_drop.get(), G_TYPE_STRING, G_PRIORITY_DEFAULT, m_cancellable.get(), [](GObject* gdkDrop, GAsyncResult* result, gpointer userData) {
     117            GUniqueOutPtr<GError> error;
     118            const GValue* value = gdk_drop_read_value_finish(GDK_DROP(gdkDrop), result, &error.outPtr());
     119            if (g_error_matches(error.get(), G_IO_ERROR, G_IO_ERROR_CANCELLED))
     120                return;
     121
     122            auto& drop = *static_cast<DropTarget*>(userData);
     123            if (value && G_VALUE_HOLDS(value, G_TYPE_STRING))
     124                drop.m_selectionData->setText(String::fromUTF8(g_value_get_string(value)));
     125            drop.didLoadData();
     126        }, this);
     127    }
     128
     129    static const char* const supportedMimeTypes[] = {
     130        "text/html",
     131        "_NETSCAPE_URL",
     132        "text/uri-list",
     133        "application/vnd.webkitgtk.smartpaste"
     134    };
     135
     136    for (unsigned i = 0; i < G_N_ELEMENTS(supportedMimeTypes); ++i) {
     137        if (!gdk_content_formats_contain_mime_type(formats, supportedMimeTypes[i]))
     138            continue;
     139
     140        m_dataRequestCount++;
     141        loadData(supportedMimeTypes[i], [this, mimeType = String::fromUTF8(supportedMimeTypes[i]), cancellable = m_cancellable](GRefPtr<GBytes>&& data) {
     142            if (g_cancellable_is_cancelled(cancellable.get()))
     143                return;
     144
     145            if (!data) {
     146                didLoadData();
     147                return;
     148            }
     149
     150            if (mimeType == "text/html"_s) {
     151                gsize length;
     152                const auto* markupData = g_bytes_get_data(data.get(), &length);
     153                if (length) {
     154                    // If data starts with UTF-16 BOM assume it's UTF-16, otherwise assume UTF-8.
     155                    if (length >= 2 && reinterpret_cast<const UChar*>(markupData)[0] == 0xFEFF)
     156                        m_selectionData->setMarkup(String(reinterpret_cast<const UChar*>(markupData) + 1, (length / 2) - 1));
     157                    else
     158                        m_selectionData->setMarkup(String::fromUTF8(reinterpret_cast<const char*>(markupData), length));
     159                }
     160            } else if (mimeType == "_NETSCAPE_URL") {
     161                gsize length;
     162                const auto* urlData = g_bytes_get_data(data.get(), &length);
     163                if (length) {
     164                    Vector<String> tokens = String::fromUTF8(reinterpret_cast<const char*>(urlData), length).split('\n');
     165                    URL url({ }, tokens[0]);
     166                    if (url.isValid())
     167                        m_selectionData->setURL(url, tokens.size() > 1 ? tokens[1] : String());
     168                }
     169            } else if (mimeType == "text/uri-list") {
     170                gsize length;
     171                const auto* uriListData = g_bytes_get_data(data.get(), &length);
     172                if (length)
     173                    m_selectionData->setURIList(String::fromUTF8(reinterpret_cast<const char*>(uriListData), length));
     174            } else if (mimeType == "application/vnd.webkitgtk.smartpaste")
     175                m_selectionData->setCanSmartReplace(true);
     176
     177            didLoadData();
     178        });
     179    }
     180}
     181
     182struct DropReadAsyncData {
     183    WTF_MAKE_STRUCT_FAST_ALLOCATED;
     184
     185    DropReadAsyncData(GCancellable* cancellable, CompletionHandler<void(GRefPtr<GBytes>&&)>&& handler)
     186        : cancellable(cancellable)
     187        , completionHandler(WTFMove(handler))
     188    {
     189    }
     190
     191    GRefPtr<GCancellable> cancellable;
     192    CompletionHandler<void(GRefPtr<GBytes>&&)> completionHandler;
     193};
     194
     195void DropTarget::loadData(const char* mimeType, CompletionHandler<void(GRefPtr<GBytes>&&)>&& completionHandler)
     196{
     197    const char* mimeTypes[] = { mimeType, nullptr };
     198    gdk_drop_read_async(m_drop.get(), mimeTypes, G_PRIORITY_DEFAULT, m_cancellable.get(), [](GObject* gdkDrop, GAsyncResult* result, gpointer userData) {
     199        std::unique_ptr<DropReadAsyncData> data(static_cast<DropReadAsyncData*>(userData));
     200        GRefPtr<GInputStream> inputStream = adoptGRef(gdk_drop_read_finish(GDK_DROP(gdkDrop), result, nullptr, nullptr));
     201        if (!inputStream) {
     202            data->completionHandler(nullptr);
     203            return;
     204        }
     205
     206        auto* cancellable = data->cancellable.get();
     207        GRefPtr<GOutputStream> outputStream = adoptGRef(g_memory_output_stream_new_resizable());
     208        g_output_stream_splice_async(outputStream.get(), inputStream.get(),
     209            static_cast<GOutputStreamSpliceFlags>(G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET),
     210            G_PRIORITY_DEFAULT, cancellable, [](GObject* stream, GAsyncResult* result, gpointer userData) {
     211                std::unique_ptr<DropReadAsyncData> data(static_cast<DropReadAsyncData*>(userData));
     212                GUniqueOutPtr<GError> error;
     213                gssize writtenBytes = g_output_stream_splice_finish(G_OUTPUT_STREAM(stream), result, &error.outPtr());
     214                if (writtenBytes <= 0) {
     215                    data->completionHandler(nullptr);
     216                    return;
     217                }
     218                GRefPtr<GBytes> bytes = adoptGRef(g_memory_output_stream_steal_as_bytes(G_MEMORY_OUTPUT_STREAM(stream)));
     219                data->completionHandler(WTFMove(bytes));
     220            }, data.release());
     221    }, new DropReadAsyncData(m_cancellable.get(), WTFMove(completionHandler)));
    55222}
    56223
    57224void DropTarget::didLoadData()
    58225{
    59 }
    60 
    61 void DropTarget::enter(IntPoint&&, unsigned)
    62 {
    63 }
    64 
    65 void DropTarget::update(IntPoint&&, unsigned)
    66 {
     226    if (--m_dataRequestCount)
     227        return;
     228
     229    m_cancellable = nullptr;
     230
     231    if (!m_position) {
     232        // Enter hasn't been emitted yet, so just wait for it.
     233        return;
     234    }
     235
     236    // Call enter again.
     237    enter(IntPoint(m_position.value()));
     238}
     239
     240void DropTarget::enter(IntPoint&& position, unsigned)
     241{
     242    m_position = WTFMove(position);
     243    if (m_cancellable)
     244        return;
     245
     246    auto* page = webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(m_webView));
     247    ASSERT(page);
     248    page->resetCurrentDragInformation();
     249
     250    DragData dragData(&m_selectionData.value(), *m_position, *m_position, gdkDragActionToDragOperation(gdk_drop_get_actions(m_drop.get())));
     251    page->dragEntered(dragData);
     252}
     253
     254void DropTarget::update(IntPoint&& position, unsigned)
     255{
     256    m_position = WTFMove(position);
     257    if (m_cancellable)
     258        return;
     259
     260    auto* page = webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(m_webView));
     261    ASSERT(page);
     262
     263    DragData dragData(&m_selectionData.value(), *m_position, *m_position, gdkDragActionToDragOperation(gdk_drop_get_actions(m_drop.get())));
     264    page->dragUpdated(dragData);
    67265}
    68266
    69267void DropTarget::didPerformAction()
    70268{
     269    if (!m_drop)
     270        return;
     271
     272    auto* page = webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(m_webView));
     273    ASSERT(page);
     274
     275    auto operation = page->currentDragOperation();
     276    if (operation == m_operation)
     277        return;
     278
     279    m_operation = operation;
     280    gdk_drop_status(m_drop.get(), dragOperationToGdkDragActions(m_operation), dragOperationToSingleGdkDragAction(m_operation));
    71281}
    72282
    73283void DropTarget::leave()
    74284{
    75 }
    76 
    77 void DropTarget::drop(IntPoint&&, unsigned)
    78 {
     285    g_cancellable_cancel(m_cancellable.get());
     286    m_drop = nullptr;
     287    m_position = WTF::nullopt;
     288    m_selectionData = WTF::nullopt;
     289    m_cancellable = nullptr;
     290}
     291
     292void DropTarget::drop(IntPoint&& position, unsigned)
     293{
     294    m_position = WTFMove(position);
     295    auto* page = webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(m_webView));
     296    ASSERT(page);
     297
     298    DragData dragData(&m_selectionData.value(), *m_position, *m_position, gdkDragActionToDragOperation(gdk_drop_get_actions(m_drop.get())));
     299    page->performDragOperation(dragData, { }, { }, { });
     300    gdk_drop_finish(m_drop.get(), gdk_drop_get_actions(m_drop.get()));
    79301}
    80302
Note: See TracChangeset for help on using the changeset viewer.