bug 1216916 clean up when InvokeDragSession() fails r=roc
authorKarl Tomlinson <karlt+@karlt.net>
Wed, 21 Oct 2015 22:16:40 +1300
changeset 302304 01e2ab74a7f8570b76b4d0f5305bf5d6a8bb27f1
parent 302303 f75a73d4731589b218f2c3d3a0308634a923f02e
child 302305 5c2f2bdb911b5682eb2c1074799c9c472635fbd5
push id5392
push userraliiev@mozilla.com
push dateMon, 14 Dec 2015 20:08:23 +0000
treeherdermozilla-beta@16ce8562a975 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs1216916
milestone44.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
bug 1216916 clean up when InvokeDragSession() fails r=roc
widget/cocoa/nsDragService.h
widget/cocoa/nsDragService.mm
widget/gtk/nsDragService.cpp
widget/gtk/nsDragService.h
widget/nsBaseDragService.cpp
widget/nsBaseDragService.h
widget/nsDragServiceProxy.cpp
widget/nsDragServiceProxy.h
widget/windows/nsDragService.cpp
widget/windows/nsDragService.h
--- a/widget/cocoa/nsDragService.h
+++ b/widget/cocoa/nsDragService.h
@@ -25,19 +25,21 @@ extern NSString* const kCorePboardType_u
 - (NSPasteboard*)pasteboard;
 @end
 
 class nsDragService : public nsBaseDragService
 {
 public:
   nsDragService();
 
+  // nsBaseDragService
+  virtual nsresult InvokeDragSessionImpl(nsISupportsArray* anArrayTransferables,
+                                         nsIScriptableRegion* aRegion,
+                                         uint32_t aActionType);
   // nsIDragService
-  NS_IMETHOD InvokeDragSession(nsIDOMNode *aDOMNode, nsISupportsArray * anArrayTransferables,
-                               nsIScriptableRegion * aRegion, uint32_t aActionType);
   NS_IMETHOD EndDragSession(bool aDoneDrag);
 
   // nsIDragSession
   NS_IMETHOD GetData(nsITransferable * aTransferable, uint32_t aItemIndex);
   NS_IMETHOD IsDataFlavorSupported(const char *aDataFlavor, bool *_retval);
   NS_IMETHOD GetNumDropItems(uint32_t * aNumItems);
 
 protected:
--- a/widget/cocoa/nsDragService.mm
+++ b/widget/cocoa/nsDragService.mm
@@ -268,35 +268,31 @@ nsDragService::ConstructDragImage(nsIDOM
   return [image autorelease];
 
   NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
 }
 
 // We can only invoke NSView's 'dragImage:at:offset:event:pasteboard:source:slideBack:' from
 // within NSView's 'mouseDown:' or 'mouseDragged:'. Luckily 'mouseDragged' is always on the
 // stack when InvokeDragSession gets called.
-NS_IMETHODIMP
-nsDragService::InvokeDragSession(nsIDOMNode* aDOMNode, nsISupportsArray* aTransferableArray,
-                                 nsIScriptableRegion* aDragRgn, uint32_t aActionType)
+nsresult
+nsDragService::InvokeDragSessionImpl(nsISupportsArray* aTransferableArray,
+                                     nsIScriptableRegion* aDragRgn,
+                                     uint32_t aActionType)
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
 
-  nsresult rv = nsBaseDragService::InvokeDragSession(aDOMNode,
-                                                     aTransferableArray,
-                                                     aDragRgn, aActionType);
-  NS_ENSURE_SUCCESS(rv, rv);
-
   mDataItems = aTransferableArray;
 
   // put data on the clipboard
   if (NS_FAILED(SetUpDragClipboard(aTransferableArray)))
     return NS_ERROR_FAILURE;
 
   nsIntRect dragRect(0, 0, 20, 20);
-  NSImage* image = ConstructDragImage(aDOMNode, &dragRect, aDragRgn);
+  NSImage* image = ConstructDragImage(mSourceNode, &dragRect, aDragRgn);
   if (!image) {
     // if no image was returned, just draw a rectangle
     NSSize size;
     size.width = dragRect.width;
     size.height = dragRect.height;
     image = [[NSImage alloc] initWithSize:size];
     [image lockFocus];
     [[NSColor grayColor] set];
--- a/widget/gtk/nsDragService.cpp
+++ b/widget/gtk/nsDragService.cpp
@@ -307,21 +307,26 @@ nsDragService::InvokeDragSession(nsIDOMN
 
     // If the previous source drag has not yet completed, signal handlers need
     // to be removed from sGrabWidget and dragend needs to be dispatched to
     // the source node, but we can't call EndDragSession yet because we don't
     // know whether or not the drag succeeded.
     if (mSourceNode)
         return NS_ERROR_NOT_AVAILABLE;
 
-    nsresult rv = nsBaseDragService::InvokeDragSession(aDOMNode,
-                                                       aArrayTransferables,
-                                                       aRegion, aActionType);
-    NS_ENSURE_SUCCESS(rv, rv);
+    return nsBaseDragService::InvokeDragSession(aDOMNode, aArrayTransferables,
+                                                aRegion, aActionType);
+}
 
+// nsBaseDragService
+nsresult
+nsDragService::InvokeDragSessionImpl(nsISupportsArray* aArrayTransferables,
+                                     nsIScriptableRegion* aRegion,
+                                     uint32_t aActionType)
+{
     // make sure that we have an array of transferables to use
     if (!aArrayTransferables)
         return NS_ERROR_INVALID_ARG;
     // set our reference to the transferables.  this will also addref
     // the transferables since we're going to hang onto this beyond the
     // length of this call
     mSourceDataItems = aArrayTransferables;
     // get the list of items we offer for drags
@@ -372,30 +377,32 @@ nsDragService::InvokeDragSession(nsIDOMN
     GdkDragContext *context = gtk_drag_begin(mHiddenWidget,
                                              sourceList,
                                              action,
                                              1,
                                              &event);
 
     mSourceRegion = nullptr;
 
+    nsresult rv;
     if (context) {
         StartDragSession();
 
         // GTK uses another hidden window for receiving mouse events.
         sGrabWidget = gtk_window_group_get_current_grab(window_group);
         if (sGrabWidget) {
             g_object_ref(sGrabWidget);
             // Only motion and key events are required but connect to
             // "event-after" as this is never blocked by other handlers.
             g_signal_connect(sGrabWidget, "event-after",
                              G_CALLBACK(OnSourceGrabEventAfter), this);
         }
         // We don't have a drag end point yet.
         mEndDragPoint = nsIntPoint(-1, -1);
+        rv = NS_OK;
     }
     else {
         rv = NS_ERROR_FAILURE;
     }
 
     gtk_target_list_unref(sourceList);
 
     return rv;
--- a/widget/gtk/nsDragService.h
+++ b/widget/gtk/nsDragService.h
@@ -53,16 +53,20 @@ class nsDragService final : public nsBas
 {
 public:
     nsDragService();
 
     NS_DECL_ISUPPORTS_INHERITED
 
     NS_DECL_NSIOBSERVER
 
+    // nsBaseDragService
+    virtual nsresult InvokeDragSessionImpl(nsISupportsArray* anArrayTransferables,
+                                           nsIScriptableRegion* aRegion,
+                                           uint32_t aActionType) override;
     // nsIDragService
     NS_IMETHOD InvokeDragSession (nsIDOMNode *aDOMNode,
                                   nsISupportsArray * anArrayTransferables,
                                   nsIScriptableRegion * aRegion,
                                   uint32_t aActionType) override;
     NS_IMETHOD StartDragSession() override;
     NS_IMETHOD EndDragSession(bool aDoneDrag) override;
 
--- a/widget/nsBaseDragService.cpp
+++ b/widget/nsBaseDragService.cpp
@@ -220,17 +220,25 @@ nsBaseDragService::InvokeDragSession(nsI
   mEndDragPoint = nsIntPoint(0, 0);
 
   // When the mouse goes down, the selection code starts a mouse
   // capture. However, this gets in the way of determining drag
   // feedback for things like trees because the event coordinates
   // are in the wrong coord system, so turn off mouse capture.
   nsIPresShell::ClearMouseCapture(nullptr);
 
-  return NS_OK;
+  nsresult rv = InvokeDragSessionImpl(aTransferableArray,
+                                      aDragRgn, aActionType);
+
+  if (NS_FAILED(rv)) {
+    mSourceNode = nullptr;
+    mSourceDocument = nullptr;
+  }
+
+  return rv;
 }
 
 NS_IMETHODIMP
 nsBaseDragService::InvokeDragSessionWithImage(nsIDOMNode* aDOMNode,
                                               nsISupportsArray* aTransferableArray,
                                               nsIScriptableRegion* aRegion,
                                               uint32_t aActionType,
                                               nsIDOMNode* aImage,
--- a/widget/nsBaseDragService.h
+++ b/widget/nsBaseDragService.h
@@ -59,16 +59,25 @@ public:
   uint16_t GetInputSource() { return mInputSource; }
 
   int32_t TakeChildProcessDragAction();
 
 protected:
   virtual ~nsBaseDragService();
 
   /**
+   * Called from nsBaseDragService to initiate a platform drag from a source
+   * in this process.  This is expected to ensure that StartDragSession() and
+   * EndDragSession() get called if the platform drag is successfully invoked.
+   */
+  virtual nsresult InvokeDragSessionImpl(nsISupportsArray* aTransferableArray,
+                                         nsIScriptableRegion* aDragRgn,
+                                         uint32_t aActionType) = 0;
+
+  /**
    * Draw the drag image, if any, to a surface and return it. The drag image
    * is constructed from mImage if specified, or aDOMNode if mImage is null.
    *
    * aRegion may be used to draw only a subset of the element. This region
    * should be supplied using x and y coordinates measured in css pixels
    * that are relative to the upper-left corner of the window.
    *
    * aScreenX and aScreenY should be the screen coordinates of the mouse click
--- a/widget/nsDragServiceProxy.cpp
+++ b/widget/nsDragServiceProxy.cpp
@@ -18,31 +18,22 @@ NS_IMPL_ISUPPORTS_INHERITED0(nsDragServi
 nsDragServiceProxy::nsDragServiceProxy()
 {
 }
 
 nsDragServiceProxy::~nsDragServiceProxy()
 {
 }
 
-NS_IMETHODIMP
-nsDragServiceProxy::InvokeDragSession(nsIDOMNode* aDOMNode,
-                                      nsISupportsArray* aArrayTransferables,
-                                      nsIScriptableRegion* aRegion,
-                                      uint32_t aActionType)
+nsresult
+nsDragServiceProxy::InvokeDragSessionImpl(nsISupportsArray* aArrayTransferables,
+                                          nsIScriptableRegion* aRegion,
+                                          uint32_t aActionType)
 {
-  nsresult rv = nsBaseDragService::InvokeDragSession(aDOMNode,
-                                                     aArrayTransferables,
-                                                     aRegion,
-                                                     aActionType);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  nsCOMPtr<nsIDOMDocument> sourceDocument;
-  aDOMNode->GetOwnerDocument(getter_AddRefs(sourceDocument));
-  nsCOMPtr<nsIDocument> doc = do_QueryInterface(sourceDocument);
+  nsCOMPtr<nsIDocument> doc = do_QueryInterface(mSourceDocument);
   NS_ENSURE_STATE(doc->GetDocShell());
   mozilla::dom::TabChild* child =
     mozilla::dom::TabChild::GetFrom(doc->GetDocShell());
   NS_ENSURE_STATE(child);
   nsTArray<mozilla::dom::IPCDataTransfer> dataTransfers;
   nsContentUtils::TransferablesToIPCTransferables(aArrayTransferables,
                                                   dataTransfers,
                                                   child->Manager(),
--- a/widget/nsDragServiceProxy.h
+++ b/widget/nsDragServiceProxy.h
@@ -10,18 +10,17 @@
 
 class nsDragServiceProxy : public nsBaseDragService
 {
 public:
   nsDragServiceProxy();
 
   NS_DECL_ISUPPORTS_INHERITED
 
-  // nsIDragService
-  NS_IMETHOD InvokeDragSession(nsIDOMNode* aDOMNode,
-                               nsISupportsArray* anArrayTransferables,
-                               nsIScriptableRegion* aRegion,
-                               uint32_t aActionType) override;
+  // nsBaseDragService
+  virtual nsresult InvokeDragSessionImpl(nsISupportsArray* anArrayTransferables,
+                                         nsIScriptableRegion* aRegion,
+                                         uint32_t aActionType) override;
 private:
   virtual ~nsDragServiceProxy();
 };
 
 #endif // NSDRAGSERVICEPROXY_H
--- a/widget/windows/nsDragService.cpp
+++ b/widget/windows/nsDragService.cpp
@@ -165,38 +165,31 @@ nsDragService::CreateDragImage(nsIDOMNod
   }
 
   dataSurface->Unmap();
 
   return psdi->hbmpDragImage != nullptr;
 }
 
 //-------------------------------------------------------------------------
-NS_IMETHODIMP
-nsDragService::InvokeDragSession(nsIDOMNode *aDOMNode,
-                                 nsISupportsArray *anArrayTransferables,
-                                 nsIScriptableRegion *aRegion,
-                                 uint32_t aActionType)
+nsresult
+nsDragService::InvokeDragSessionImpl(nsISupportsArray* anArrayTransferables,
+                                     nsIScriptableRegion* aRegion,
+                                     uint32_t aActionType)
 {
-  nsresult rv = nsBaseDragService::InvokeDragSession(aDOMNode,
-                                                     anArrayTransferables,
-                                                     aRegion,
-                                                     aActionType);
-  NS_ENSURE_SUCCESS(rv, rv);
-
   // Try and get source URI of the items that are being dragged
   nsIURI *uri = nullptr;
 
   nsCOMPtr<nsIDocument> doc(do_QueryInterface(mSourceDocument));
   if (doc) {
     uri = doc->GetDocumentURI();
   }
 
   uint32_t numItemsToDrag = 0;
-  rv = anArrayTransferables->Count(&numItemsToDrag);
+  nsresult rv = anArrayTransferables->Count(&numItemsToDrag);
   if (!numItemsToDrag)
     return NS_ERROR_FAILURE;
 
   // The clipboard class contains some static utility methods that we
   // can use to create an IDataObject from the transferable
 
   // if we're dragging more than one item, we need to create a
   // "collection" object to fake out the OS. This collection contains
@@ -209,17 +202,17 @@ nsDragService::InvokeDragSession(nsIDOMN
       return NS_ERROR_OUT_OF_MEMORY;
     itemToDrag = dataObjCollection;
     for (uint32_t i=0; i<numItemsToDrag; ++i) {
       nsCOMPtr<nsISupports> supports;
       anArrayTransferables->GetElementAt(i, getter_AddRefs(supports));
       nsCOMPtr<nsITransferable> trans(do_QueryInterface(supports));
       if (trans) {
         // set the requestingNode on the transferable
-        trans->SetRequestingNode(aDOMNode);
+        trans->SetRequestingNode(mSourceNode);
         RefPtr<IDataObject> dataObj;
         rv = nsClipboard::CreateNativeDataObject(trans,
                                                  getter_AddRefs(dataObj), uri);
         NS_ENSURE_SUCCESS(rv, rv);
         // Add the flavors to the collection object too
         rv = nsClipboard::SetupNativeDataObject(trans, dataObjCollection);
         NS_ENSURE_SUCCESS(rv, rv);
 
@@ -228,31 +221,31 @@ nsDragService::InvokeDragSession(nsIDOMN
     }
   } // if dragging multiple items
   else {
     nsCOMPtr<nsISupports> supports;
     anArrayTransferables->GetElementAt(0, getter_AddRefs(supports));
     nsCOMPtr<nsITransferable> trans(do_QueryInterface(supports));
     if (trans) {
       // set the requestingNode on the transferable
-      trans->SetRequestingNode(aDOMNode);
+      trans->SetRequestingNode(mSourceNode);
       rv = nsClipboard::CreateNativeDataObject(trans,
                                                getter_AddRefs(itemToDrag),
                                                uri);
       NS_ENSURE_SUCCESS(rv, rv);
     }
   } // else dragging a single object
 
   // Create a drag image if support is available
   IDragSourceHelper *pdsh;
   if (SUCCEEDED(CoCreateInstance(CLSID_DragDropHelper, nullptr,
                                  CLSCTX_INPROC_SERVER,
                                  IID_IDragSourceHelper, (void**)&pdsh))) {
     SHDRAGIMAGE sdi;
-    if (CreateDragImage(aDOMNode, aRegion, &sdi)) {
+    if (CreateDragImage(mSourceNode, aRegion, &sdi)) {
       if (FAILED(pdsh->InitializeFromBitmap(&sdi, itemToDrag)))
         DeleteObject(sdi.hbmpDragImage);
     }
     pdsh->Release();
   }
 
   // Kick off the native drag session
   return StartInvokingDragSession(itemToDrag, aActionType);
--- a/widget/windows/nsDragService.h
+++ b/widget/windows/nsDragService.h
@@ -18,21 +18,20 @@ class  nsDataObjCollection;
  */
 
 class nsDragService : public nsBaseDragService
 {
 public:
   nsDragService();
   virtual ~nsDragService();
   
-  // nsIDragService
-  NS_IMETHOD InvokeDragSession(nsIDOMNode *aDOMNode,
-                               nsISupportsArray *anArrayTransferables,
-                               nsIScriptableRegion *aRegion,
-                               uint32_t aActionType);
+  // nsBaseDragService
+  virtual nsresult InvokeDragSessionImpl(nsISupportsArray* anArrayTransferables,
+                                         nsIScriptableRegion* aRegion,
+                                         uint32_t aActionType);
 
   // nsIDragSession
   NS_IMETHOD GetData(nsITransferable * aTransferable, uint32_t anItem);
   NS_IMETHOD GetNumDropItems(uint32_t * aNumItems);
   NS_IMETHOD IsDataFlavorSupported(const char *aDataFlavor, bool *_retval);
   NS_IMETHOD EndDragSession(bool aDoneDrag);
 
   // native impl.